Exercises#

You can easily start a live Jupyter session in the cloud directly from this book. To do this, just click on the Launch Button () located above on this page.

You have a few options to choose from:

  1. Launch on Binder: By selecting this option, you can instantly launch a live Jupyter session using Binder.

  2. Launch on Google Colab: This option allows you to launch a live Jupyter session using Google Colab.

Alternatively, you can also click on the Jupyter Lite session link, which will open a new tab where you can freely write and run your code.

Jupyter Lite session

You can start a Jupiter lite session here

Wait until the message “You may begin!” is printed.

(Fixing) Exercise 4.1.1#

Let’s assume that you develop a login interface for an international oil company; which, as the title international suggests, works internationally. Thus, a lot of clients worldwide expect to see data in their favorite units. The company has hired an intern to output temperatures in Celsius and Fahrenheit, from the provided temperature in Kelvin. But something went wrong, the code doesn’t work and now the intern is gone. So, the burden of fixing the code is, yet again, put on your shoulders.

import time

def get_display_temperature(temperature_kelvin):
    # copying temporarily temperature_kelvin to temperature_celsius
    temperature_celsius = temperature_kelvin
    
    # converting kelvin to celsius
    for i in range(len(temperature_celsius)):
        temperature_celsius[i] = temperature_celsius[i] - 273.15
        
    # copying temporarily temperature_kelvin to temperature_fahrenheit
    temperature_fahrenheit = temperature_kelvin
    
    # converting kelvin to fahrenheit
    for i in range(len(temperature_fahrenheit)):
        temperature_fahrenheit[i] = (temperature_fahrenheit[i] - 273.15) * (9 / 5) + 32
    
    # now, creating display messages from the converted temperatures
    display_messages = []
    for i in range(len(temperature_kelvin)):
        msg = (
            f"{temperature_celsius[i]:<10.3f}°C | {temperature_fahrenheit[i]:<10.3f}"
            f"°F (ID={i})"
        )
        display_messages.append(msg)
        
    return display_messages

def update_screen_text(messages):
    for msg in messages:
        print(msg, end='\r')
        time.sleep(1)
        

temperature_kelvin = [300.67, 277.56, 315.88, 307.87, 100]
messages = get_display_temperature(temperature_kelvin)
update_screen_text(messages)
-771.340  °C | -771.340  °F (ID=4)

check your answer!

To check your answer in a Jupyter Lite session, simply run the following line of code immediately after your code implementation.

If your are in Google Colab just run the cell bellow.

check.notebook_4(question_number=0, arguments[get_display_temperature])

(Fixing) Exercise 4.1.2#

The main philosophy of programming is avoiding redundancy — you shouldn’t write the same batch code two or more times if you can just create a function out of it. The same can be applied to many other things — don’t start a new assignment from scratch, if you can re-use a formatting template from your previous assignments. In the cell with code below, you see an example of preparing a template for observation of some satellite, which can work in 2 different modes, and thus will have a slightly different template for each of the modes. The code below is supposed to do that and it was even tested!

import time

def prepare_template(default_bands, observation_mode):  
    #creating metadata for the upcoming observations
    template = {'time': time.ctime(time.time()),
               'observation_mode': observation_mode,
               'bands': default_bands}
    
    #adding additional bands for the extended mode
    if observation_mode == 'normal':
        #no need to add bands
        pass
    elif observation_mode == 'extended':
        template['bands'] += ['B8', 'B8A']
    else:
        #if the mode is unknonw - raise a RuntimeError
        raise RuntimeError(
            f'Failed to identify observation mode: {observation_mode}'
            )
        
    return template

def print_dict(my_dict):
    for key, value in my_dict.items():
        print(f'{key} -> {value}')  


"set of default bands, don't change!!"
default_bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']

Lets test the the function

  • Test 1. - normal mode.

    Expected behavior: a dictionary with 3 items and only default bands are inside

print('Test 1')
template_normal = prepare_template(default_bands, 'normal')
print_dict(template_normal)
Test 1
time -> Thu Jun  8 10:45:40 2023
observation_mode -> normal
bands -> ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A']
  • Test 2. - extended mode.

    Expected behavior: a dictionary with 3 items and extended list of bands.

print('Test 2')
template_extended = prepare_template(default_bands, 'extended')
print_dict(template_extended)
Test 2
time -> Thu Jun  8 10:46:18 2023
observation_mode -> extended
bands -> ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B8', 'B8A']
  • Test 3. - any other observation mode.

    Expected behavior: Runtime error

print('test 3')
template_error = prepare_template(default_bands, 'should raise an error, right?')
test 3
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[18], line 2
      1 print('test 3')
----> 2 template_error = prepare_template(default_bands, 'should raise an error, right?')

Cell In[12], line 17, in prepare_template(default_bands, observation_mode)
     14     template['bands'] += ['B8', 'B8A']
     15 else:
     16     #if the mode is unknonw - raise a RuntimeError
---> 17     raise RuntimeError(f'Failed to identify observation mode: {observation_mode}')
     19 return template

RuntimeError: Failed to identify observation mode: should raise an error, right?

Looks good, however, if you rearrange the extended and normal tests, it won’t work anymore, look at the output below to see this.

#set of default bands, don't change!!!
default_bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']

template_extended = prepare_template(default_bands, 'extended')
template_normal = prepare_template(default_bands, 'normal')

print('Test 1')
print_dict(template_extended)
print('-------------------')
print('Test 2')
print_dict(template_normal)
Test 1
time -> Thu Jun  8 10:50:12 2023
observation_mode -> extended
bands -> ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A']
-------------------
Test 2
time -> Thu Jun  8 10:50:12 2023
observation_mode -> normal
bands -> ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A']

Obviously, the order of tests shouldn’t matter, so, most likely, the problem is with the function itself. Please fix the function, in the cell above, so that the second set of tests also works (you can comment out the first set of tests if you want).

check your answer!

To check your answer in a Jupyter Lite session, simply run the following line of code immediately after your code implementation.

If your are in Google Colab just run the cell bellow.

check.notebook_4(question_number=1,arguments=[prepare_template])