Functions, exceptions, modules#

Functions#

The print function#

print is one of the most frequently used functions. It prints all the arguments passed to it, puts a space between them, and at the end moves to a new line.

Let’s look at an example:

print('first argument', 'second', '=', 5.)
first argument second = 5.0

For more general use, see the documentation:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False),

where the arguments are:

  • *objects represents the arguments we want to print (the full meaning of the asterisk will become clear when we discuss functions, below),

  • sep is the separator string,

  • end is the terminating string,

  • file is the output file (sys.stdout is the standard output, which in this particular case means the screen, i.e. the command line; we will change this later),

  • flush, when True, finalizes the output (otherwise, due to optimization, it may remain in the buffer).

For the end argument above we used a so-called escape character: \.

The purpose of the escape character is to give the following character a special meaning; some common uses are:

  • \n inserts a line break,

  • \t inserts a tab,

  • \b deletes the previous character (backspace),

  • ' prints a single quote ‘,

  • " prints a double quote “,

  • \ displays the backslash,

  • \ new line in a multiline string.

Example (how we usually do not program):

print('fi','ve', sep='-', end='=')
print('5:)')
fi-ve=5:)

And one more example with escape characters:

print('Strings in Python (per PEP8) should not be longer than 80 characters. \
The reason is that we do not have to scroll the window left and right. \
So that we can still write strings that are longer than 80 characters, \
we use a single separator character \\ (note how it \
is printed: \\)',)
Strings in Python (per PEP8) should not be longer than 80 characters. The reason is that we do not have to scroll the window left and right. So that we can still write strings that are longer than 80 characters, we use a single separator character \ (note how it is printed: \)

String formatting#

For formatting strings we have several tools available:

Let’s look at some examples:

a = 3.14
print(f'pi = {a}')                # f-string
print('pi = {a}'.format(a = a))   # .format
print('pi = %(a)3.2f' % {'a': a}) # %
pi = 3.14
pi = 3.14
pi = 3.14

The f-string has been implemented since Python version 3.6 (PEP 498) and is the simplest way of formatting. We mention the other approaches only so that the reader becomes acquainted with them and so that we can link to the documentation.

An f-string always begins with f before the first quote and allows very general formatting (see the documentation).

The value we want to format inside the string is placed in curly braces:

f'text... {arg_name1:fmt1} ... text...'

Inside the curly braces:

  • before : we give the name of the value we want to format

  • after : we format how the variable is printed; most often we will use the fmt forms:

    • w.df - floating-point representation (float)

    • w.de - representation with an exponent (exponent)

    • w.dg - general format (general)

    • ws - string of characters (string).

w is the (minimum) total width, and d is the number of digits after the decimal point.

Let’s look at an example:

height = 1.84
name = 'Marko'
text = f'{name} is {height} m tall, or also: {height:e} m, {height:7.3f} m.'
text
'Marko is 1.84 m tall, or also: 1.840000e+00 m,   1.840 m.'

We could do the same with the format method by referring to the argument index:

text = '{1} is {0} m tall, or also: {0:e} m, {0:7.3f} m.'.format(height, name)
text
'Marko is 1.84 m tall, or also: 1.840000e+00 m,   1.840 m.'

Example using a dictionary:

parameters = {'height': 5., 'density':100.111, 'user name': 'Janko'}
f'height = {parameters["height"]:7.3f}, density = {parameters["density"]:7.3e}'
'height =   5.000, density = 1.001e+02'

Formatting with fmt (the Format Specification Mini-Language) is extremely rich. The part after the colon has the general form (see the documentation):

[[fill]align][sign][#][0][width][grouping_option][.precision][type]

where the parameters in square brackets are optional (all of them are optional):

  • fill can be any character,

  • align specifies the alignment, options: "<" | ">" | "=" | "^",

  • sign specifies the sign, options: "+" | "-" | " ",

  • width defines the minimum total width,

  • grouping_option grouping options, options: "_" | ","

  • precision defines the number of digits after the decimal separator,

  • type defines how the data should be displayed, options: "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | ""o" | "s" | "x" | "X" | "%"

We align text to the left with "<", to the right with ">", and centered with "^". Example of centered/right alignment (width 20 characters):

f'{height:*^20}' # before ^ is the character we use to fill the left and right sides
'********1.84********'
f'{parameters["height"]:_>20}'
'_________________5.0'
c = 4-2j
f'The complex number {c} consists of a real ({c.real})\
and an imaginary ({c.imag}) part.'
'The complex number (4-2j) consists of a real (4.0)and an imaginary (-2.0) part.'

You can look at formatting of date and time in the appendix below.

File handling#

File handling is important, since we often store data in files or read it from them. A file we want to read from or write to must first be opened. We do this with the open command (documentation):

open(file, mode='r', buffering=-1, encoding=None,
    errors=None, newline=None, closefd=True, opener=None)

Of all the arguments, only file is required; it defines the path to the file.

The mode argument can be:

  • 'r' for reading (read, default),

  • 'w' for writing (write, the file is cleared first),

  • 'x' for exclusive writing; if the file already exists it returns an error,

  • 'a' for appending to the end of an existing file (append),

  • 'b' binary format,

  • 't' text format (default),

  • '+' the file is opened for both reading and writing.

The last three ('b', 't', '+') are used in combination with the first three ('r', 'w', 'x'). Example: mode='r+b' means reading and writing a binary file.

We will look in more detail only at reading and writing text files.

The other (optional) arguments of the open function are described in detail in the documentation.

The default is mode='r' (i.e. 'rt', since text mode is the default), which means the file is opened for reading in text form.

Let’s first look at writing to a (text) file (mode='w'):

file = open('data/prikaz vpisa.txt', mode='w')

'data/prikaz vpisa.txt' is a relative path (relative to the location where the Jupyter notebook is run) to the file.

Let’s write the first line using the write method:

file.write('test of the first line\n')
23

The write method returns the number of characters written. If you check the contents of the file at this moment, it is very likely still empty. The reason is that the content is still in the buffer, which is flushed to disk only occasionally or when the file is closed (the reason for this behavior is the speed of writing to disk; for details see the documentation of the buffering argument of the open function).

Let’s write the second line:

file.write('second line\n', )
12

Now let’s also enter some numerical values:

for d in range(5):
    file.write(f'{d:7.2e}\t {d:9.4e}\n')

We close the file:

file.close()

Now we open the file for reading and writing, mode='r+':

file = open('data/prikaz vpisa.txt', mode='r+')

Let’s check all the lines with a for loop; in the code below, file returns one line on each iteration:

for line in file:
    print(line, end='')
test of the first line
second line
0.00e+00	 0.0000e+00
1.00e+00	 1.0000e+00
2.00e+00	 2.0000e+00
3.00e+00	 3.0000e+00
4.00e+00	 4.0000e+00

In the introduction to the print function we mentioned the file argument, which defines the file to write to (the default is the standard output, i.e. the screen). If we pass as the file argument a file that is opened for writing:

print('end', file=file)
file.close()

the content is written to the file. You can check the result in the file!

This is a nice opportunity to learn about the with statement (documentation). The full scope of the with statement goes beyond the purpose of this course, but its use in file handling is very simple, so let’s look at an example:

with open('data/prikaz vpisa.txt') as file:
    for line in file:
        print(line, end='')
test of the first line
second line
0.00e+00	 0.0000e+00
1.00e+00	 1.0000e+00
2.00e+00	 2.0000e+00
3.00e+00	 3.0000e+00
4.00e+00	 4.0000e+00
end

The with statement stores the result of the open function in (as) the name file, and then we print the values for each line. When exiting the with statement, the file.close() method is called automatically. The with statement therefore allows us to write clear and compact code.

Functions in general#

Python has many functions already built in (see the documentation); but we can also write functions ourselves or import them from so-called modules (above we imported datetime, more on this later).

A generic example of a function is (documentation):

def function_name(parameters):
    '''docstring'''
    [code]
    return content

Here we point out:

  • def denotes the definition of a function,

  • function_name per PEP8, function names are written in lowercase, with multiple words joined by an underscore,

  • parameters the parameters of the function, more on which below,

  • docstring (optional) the documentation of the function,

  • [code] the code of the function,

  • return (optional) the command to exit the function; whatever follows is returned as the result (if there is no return, or nothing after return, then None is returned)

Example of a simple function:

def area(length, width):
    S = length * width
    return S
area(1, 20)
20

Passing arguments to functions#

Python knows two ways of passing arguments:

  • by position (positional)

  • by name.

Let’s look at both ways with an example:

area(3, 6) # positional
18
area(width = 3, length = 6) # by name
18

It is recommended to pass arguments by name; this reduces the chance of error!

If we do not give a name, then the name is assumed based on the order of the arguments; example:

area(3, width=4)
12

When we mix positional and named argument passing, the positional arguments must come first, and only then the named ones. At the same time, a named argument must not redefine a positional one; since length is the first argument, calling code like this:

area(3, length=4)

would cause an error.

Example of good practice when defining arguments#

We often extend functions and add new arguments, or sometimes we cannot even define the number of arguments to a function in advance!

Python has no problem with this. Arguments that are not explicitly defined are handled with:

  • *[name0] the tuple [name0] contains all positional arguments that are not explicitly defined,

  • **[name1] the dictionary [name1] contains all named arguments that are not explicitly defined.

Let’s look at an example:

def some_function(student, exam = True):
    ''' First version of the function'''
    print(f'Student {student} has registered for the exam: {exam}.')
some_function('Janez', exam=True)
Student Janez has registered for the exam: True.

Now let’s prepare a second, upgraded version (it allows the same use as the first version):

def some_function(*args_tuple, **kwargs_dict):
    ''' Second version of the function '''
    student = args_tuple[0]
    exam = kwargs_dict.get('exam', True) # True is the default value
    print_figure = kwargs_dict.get('print_figure', False) # False is the default value

    print(f'Student {student} has registered for the exam: {exam}.')
    if print_figure:
        print('figure:)')
some_function('Janez', exam=True)
Student Janez has registered for the exam: True.
some_function('Janez', exam=True, print_figure=True, nonexistent_argument='no')
Student Janez has registered for the exam: True.
figure:)

Passing functions as an argument#

Here we would like to point out that arguments can also be other functions.

Let’s look at an example:

def format_a(value):
    return f'Display of value: {value}'

def format_b(value):
    return f'Display of value: {value:3.2f}'

def display(formatter, value):
    print(formatter(value))

So we have two functions, format_a and format_b, which format a numerical value slightly differently.

Let’s look at their use:

display(format_a, 3)
Display of value: 3
display(format_b, 3)
Display of value: 3.00

Function docstring#

The docstring is an optional part of a function definition that documents the function and its use. From this point of view, it is highly recommended to use it.

The documentation for the docstring lists the essential elements:

  • the first line should be a short summary of the function,

  • if there are multiple lines, the second should be blank (to visually separate the first line from the rest of the text),

  • use three quotes (double “ or single ‘), which denote a multiline string of characters.

Example of a documented function:

def area(length = 1, width = 10):
    """ Computation of the area of a rectangle

    The function returns the value of the area.

    Arguments:
    length: length of the rectangle
    width: width of the rectangle
    """
    return length * width

Example of a call with default arguments (while calling the function you can press [shift]+[tab] to access the help):

area()
10

Local/global names#

A simple rule of thumb for functions is: a function sees out, but others do not see in. A function has internal names that do not collide with the same names in other functions.

Let’s look at an example:

outer = 3
def first():
    inner = 5
    print(f'This is the outer value: {outer}, and this is the inner one: {inner}')
first()
This is the outer value: 3, and this is the inner one: 5

Since the name inner is not defined outside the function first, calling:

inner

outside the function would return an error (we cannot see into the function).

Here it is worth mentioning that passing external names into a function outside of the function’s arguments is discouraged.

return#

The return command returns values from a function. So far we have seen results in the form of a single variable; but this variable can also be a tuple.

Let’s look at an example:

def return_tuple():
    return 1, 2, 3 # this is an equivalent way of writing the tuple: (1, 2, 3)
return_tuple()
(1, 2, 3)

We can capture the result of the function like this:

result = return_tuple()
result
(1, 2, 3)

Or by unpacking the values (this is generally true for tuples):

i1, i2, i3 = return_tuple()
i1 # printing only one value
1

Anonymous function/expression#

An anonymous function (see the documentation) is a function to which we do not give a name (which is why it is anonymous), but instead define it with the lambda command. A typical use is:

lambda [parameter list]: expression

We will look at the lambda function with a sorting example:

lst = [-4, 3, -8, 6]

from the smallest to the largest value. We can do this with the built-in sort method (documentation):

sort(*, key=None, reverse=False)

The method has two optional arguments:

  • key the key by which we sort the elements

  • reverse, if False, the comparison between key values uses <, otherwise >.

Note: list.sort() performs the sorting on the existing list and does not return a list. The sorted() function (see the documentation), however, returns a list of the sorted values.

Let’s look at an example:

lst = [-4, 3, -8, 6]
lst.sort()
lst
[-8, -4, 3, 6]

Now let’s use a key where the squared value is used for comparing the sorting values:

lst.sort(key = lambda a: a**2)
lst
[3, -4, 6, -8]

Handling exceptions#

While programming, exceptions occur relatively often; for example: division by zero.

1/0

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-50-05c9758a9c21> in <module>()
----> 1 1/0

ZeroDivisionError: division by zero

In case of an exception, Python warns about it and interrupts execution. It is not good for a program to be interrupted or to crash; for this reason a beginner programmer would probably handle the above situation with an if statement. However, such an approach is neither very practical nor general, and that is why exception handling has become established in most modern programming languages.

We will look at some basics that will above all make it easier for students to read and understand the code of other authors.

We handle exceptions with the try statement:

try:
    [code0]
except:
    [code1]
finally:
    [code2]

In the try statement, except is executed if an exception occurs in the code [code0]; finally is optional and is executed in any case when exiting the try statement.

Let’s look at an example where we simply continue execution:

try:
    1/0
except:
    pass

We use the pass command when the syntax requires a statement (code) to execute, but we do not want any action (see the documentation).

With except we can also catch different exceptions; we do it like this:

try:
    1/0
except ZeroDivisionError:
    print('Division by zero!') # or some other action
except:
    print('Unexpected error.') # discouraged; it is good to anticipate the error!
Division by zero!

Now let’s use the same code for the case of dividing a number by a string:

try:
    1/'this just will not work'
except ZeroDivisionError:
    print('Division by zero!') # or some other action
except:
    print('Unexpected error.') # discouraged; it is good to anticipate the error!
Unexpected error.

Raising exceptions#

We can also raise exceptions ourselves; we do this with the raise command (documentation).

An example of raising an error is:

raise Exception('Description of the exception')

a simple but complete example, where we would expect person_name to be of type str:

person_name = 1
try:
    if type(person_name) != str:
        raise Exception(f'The name is not of the expected type `str`.')
except Exception as exception:
    print(exception)
The name is not of the expected type `str`.

Basics of modules#

With modules we can easily reuse already-written code. Simply put, modules in Python allow us to relatively easily maintain clarity and order. Usually we package some self-contained function, a group of functions, or, for example, an object into a module (later we will learn what an object is).

For a detailed description of importing modules, see the documentation.

In the modules folder there is a file first_module.py with the following content:

def square(x=1):
    return x**2

Important: we often arrange modules hierarchically into directories. Only if a given directory contains a file (it can even be empty) named __init__.py, will such a directory behave as a module. In the example above, such a file exists, and consequently the modules folder behaves as a module, and within this module there is a submodule first_module (and the file is first_module.py).

We typically import modules in two ways:

First way:

from modules import first_module

in this case we import the namespace first_module; this means that we call the function square() like this: first_module.square().

Second way of importing a module:

import modules

We import the namespace modules; this means that we call the function square() like this: modules.first_module.square().

If we want to import the functions in the first_module module, we do it like this:

from modules import first_module

Now we can call the square function like this:

first_module.square(5)
25

With the from command we can import only part of a module. Example:

from modules.first_module import square

Now we call the square function directly:

square(6)
36

We can also rename functions or modules. Example:

from modules.first_module import square as sqr
sqr(7)
49

Where does Python look for modules?

  1. In the current folder (the one in which you launched jupyter notebook),

  2. in the folders defined in PYTHONPATH,

  3. in the folders where Python is installed (the site-packages subdirectory).

Importing modules and the Jupyter notebook#

In this book, for pedagogical reasons, we will always import modules at the point where we first need them. The rules of good practice and clear code recommend that the imports of all modules be done at the top of the Jupyter notebook!

The pickle module#

We will often use the pickle module for very fast and compact storing and reading of data. pickle stores the values of a variable in the same form as they are written in memory. In the case of real numbers, it therefore does not lose accuracy (writing to text form loses accuracy, since we define the number of printed digits, which can be smaller than the number of decimal places in memory). In addition, the representation in memory is usually less demanding than the representation in text form. Since the values do not need to be converted to/from text form, writing/reading is also very fast! Here we will look at the basic usage; pickle is described comprehensively in the documentation.

pickle has two important methods:

  • dump(obj, file, protocol=None, *, fix_imports=True) for storing the object obj,

  • load(file, *, fix_imports=True, encoding="ASCII", errors="strict") for reading the file file.

We will look at the usage with an example. First we import the module:

import pickle

Let’s write the values of the dictionary a to the file data/stanje1.pkl:

a = {'number': 1, 'size': 10}

with open('data/stanje1.pkl', 'wb') as file:
    pickle.dump(a, file, protocol=-1) # note: use protocol=-1 to use the latest version

Note that the file was opened for writing in binary form wb. It is also important that we use the latest version of the protocol (the protocol parameter); the default one is not optimized for speed and does not write in binary form.

Now let’s read the values back into b and display it:

with open('data/stanje1.pkl', 'rb') as file:
    b = pickle.load(file)

b
{'number': 1, 'size': 10}

Above we claimed that the approach is very fast; let’s verify this.

First we prepare the data (a list of 50000 values of type int):

data = list(range(50000))

Writing in text form

%%timeit
file = open('data/data.txt', mode='w')
for d in data:
    file.write(f'{d:7.2e}\n' )
file.close()
22.5 ms ± 89.5 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Writing with pickle:

%%timeit
with open('data/data.pkl', 'wb') as file:
    pickle.dump(data, file, protocol=-1)
899 μs ± 24.5 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

That is almost a 20-fold speedup!

Using modules from the internet#

In addition to the built-in modules and those we prepare ourselves, there is also a large set of modules that we can find on the internet and that add new functionality to Python. It is these modules that make the Python ecosystem so useful.

Technically, a module is a single file; when some larger module contains several modules, we can start talking about packages. We will learn about the most important packages in the field of engineering sciences within this book.

We can update modules or packages, or install new ones; for this we are helped by so-called package managers. The most common package manager is pip (documentation).

The pip package manager#

pip is a package manager with a long history and supports a large number of packages (pypi.org).

We find already installed packages with a command in the command line (documentation):

pip list

Instead of output to the command line, we will often use the option of the Jupyter notebook where, with an exclamation mark (!) in a code cell, we execute a command in the command line (this is a short form of the magic command %sx - shell execute, see the documentation). Note: two exclamation marks would return the entire result directly into the notebook (since the output is very long, we avoided this).

Let’s look at an example:

result = !pip list
result[:5]
['Package                       Version',
 '----------------------------- -----------',
 'accessible-pygments           0.0.5',
 'alabaster                     0.7.16',
 'anyio                         4.13.0']

We install packages with the command (in the command line):

pip install [package_name]

we update with:

pip install [package_name] --upgrade

and we remove with:

pip uninstall [package_name]

For more, see the documentation.

Example of installing a package#

Otherwise, we most often find packages on the internet (pypi.org). Go to the mentioned portal and look for packages on the topic of downloading videos from www.youtube.com. By searching for “pytube” we find a promising package, which we install:

Now let’s use the module (for usage details see the documentation). First we import the entire package:

import pytube
yt = pytube.YouTube('https://www.youtube.com/watch?v=P4IrAXbpeyI') # we create an instance of the object (what exactly this means, we will learn later)
yt.streams.get_highest_resolution().download() # We download the video
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[61], line 1
----> 1 import pytube
      2 yt = pytube.YouTube('https://www.youtube.com/watch?v=P4IrAXbpeyI') # we create an instance of the object (what exactly this means, we will learn later)
      3 yt.streams.get_highest_resolution().download() # We download the video

ModuleNotFoundError: No module named 'pytube'

Additional#

Formatting date and time#

First we import the module for working with date and time, datetime, and display the current time with the date (we use the now() function):

import datetime
now = datetime.datetime.now()
now
datetime.datetime(2024, 1, 4, 14, 35, 58, 68563)

We format the time information:

f'{now:%Y-%m-%d %H:%M:%S}'
'2024-01-04 14:35:58'

Formatting date and time follows these methods:

  • strftime (documentation) is used to convert from datetime to a string of characters,

  • strptime (documentation) is used to convert from a string of characters to the datetime type.

How to print the appropriate form (i.e. how to use the characters %Y, %m, etc.) is likewise explained in detail in the documentation.

Let’s look at an example of converting the datetime type to a string (relative to the above, we added %a so that the name of the day is printed):

now.strftime('%Y-%m-%d %H:%M:%S %a')
'2024-01-04 14:35:58 Thu'

Now in the opposite direction, i.e. from a string to datetime:

datetime.datetime.strptime('2017-09-28 05:31:45', '%Y-%m-%d %H:%M:%S')
datetime.datetime(2017, 9, 28, 5, 31, 45)

Some modules#

  1. openpyxl for writing and reading Excel xlsx/xlsm files: source,

  • Regular expressions (a very powerful tool for searching through strings): source.

The sys module#

Python has a large number of built-in modules (and many more can be downloaded from the internet, e.g. here) that add various functionalities.

The sys module provides access to objects used by the interpreter.

Let’s look at an example; first we import the module:

import sys

We can check the folders where modules are searched for with the command sys.path (documentation):

sys.path
['c:\\_j\\Work Janko\\Pedagosko delo\\_predavanja\\Programiranje in numericne metode\\pynm\\notebooks',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\python311.zip',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\DLLs',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\Lib',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311',
 '',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\win32',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\win32\\lib',
 'C:\\Users\\janko\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\Pythonwin']

The os module#

The os module is intended for working with the operating system and takes care of compatibility across different operating systems (if, for example, you write a program on a Windows system, it will also work on a linux system).

We import the module:

import os

We look at the current folder:

os.path.curdir
'.'

or the current folder in absolute form:

os.path.abspath(os.path.curdir)
'c:\\_j\\Work Janko\\Pedagosko delo\\_predavanja\\Programiranje in numericne metode\\pynm\\notebooks'

How do we find all the files and folders in a directory?

lst = os.listdir()

Let’s display the first four with the ipynb extension:

i = 0
for name in lst:
    if os.path.isfile(name):
        if name[-5:] == 'ipynb':
            print(f'I found a file: {name:s}')
            i +=1
        if i>3:
            break
Našel sem datoteko: Predavanje 01 - Uvod v Python.ipynb
Našel sem datoteko: Predavanje 02 - Print, delo z datotekami, funkcije, moduli.ipynb
Našel sem datoteko: Predavanje 03 - Moduli, numpy, matplotlib.ipynb
Našel sem datoteko: Predavanje 04 - Objektno programiranje, simbolno računanje.ipynb

For more, see the documentation.


Exercise questions#


The print function, string formatting#

Question 1: Write your first and last name into an arbitrarily named string. Using the print function and f-strings, print arbitrary text in which you also include the prepared string.

Question 2: For all natural numbers from 1 to 10, in a for loop print '10 / <number> = <division result>'. Use the print function and f-strings! Show different formatting options.

Question 3: Using the print function and f-strings, write the data from a dictionary in tabular form, '<key> \t <value>' (hint: dictionary.items()).

data = {'a': 0, 'F': 1013, 'k': 0.19, 'H': 55, 'l': 19.22, 'n': 7, 'v': 77.6}

Functions#

Question 4: Define a function that accepts several unnamed arguments and returns their sum.

Question 5: Define a function that accepts several named arguments. If you pass it a mass m and a velocity v as arguments, it should return the kinetic energy, \(\frac{1}{2}m~v^2\).

File handling#

Question 6: Following the model of one of the tasks above, write the data from a dictionary in tabular form into a text file.

file_path = './/data//tabela.txt'
data

Question 7: Read the previously written text file, and store all the lines in a list.

file_path

Question 8: Define a function read_lines that reads an arbitrary text file and returns a list of all its lines. Its argument should be the path to the file.

Comprehensions of lists, tuples, dictionaries…#

Question 9: Convert the numerical data values, which are stored as strings in the list above, into floating-point numbers. Use a list comprehension.


Error and exception control#

Question 10: For all values i in range(-10,10), store the result of 10 / i in a list. Use a list comprehension. Catch and print the exceptions.

Question 11 Upgrade the read_lines function from one of the previous tasks, which reads a text file and returns a list of all its lines, so that in the case of an incorrectly provided path it catches and prints the error.


Modules#

Question 12: Save the function from the previous task into the moj_modul folder, in the module moja_funkcija.py. Import the module and use the function.

from moj_modul.moja_funkcija import read_lines as read_lines_from_module