Data Science Lab
Python Programming
DataBase and Data Mining Group Andrea Pasini, Elena Baralis
Summary
▪ Python language
▪ Python data types
▪ Controlling program flow
▪ Functions
▪ Lambda functions
▪ List comprehensions
▪ Classes
▪ Structuring Python programs
2
Python data types
▪ Python is an object oriented language
▪ Every piece of data in the program is an Object
▪ Objects have properties and functionalities
▪ Even a simple integer number is a Python object
Example of an integer object
type: int
id: 140735957856544
value: 3
3
Python data types
▪ Reference = symbol in a program that refers to
a particular object
▪ A single Python object can have multiple
references (alias)
references integer object
x type: int
id: 140735957856544
value: 3
y
4
Python data types
▪ In Python
▪ Variable = reference to an object
▪ When you assign an object to a variable it
becomes a reference to that object
variables (references) integer object
x type: int
id: 140735957856544
value: 3
y
5
Python data types
▪ Defining a variable
▪ No need to specify its data type
▪ Just assign a value to a new variable name
a = 3
a type: int
id: 140735957856544
value: 3
6
Python data types
▪ Example
x
x = 5.6 type: float
y = x value: 5.6
▪ If you assign y to a new value...
x type: float
y = 3
value: 5.6
type: int
y
value: 3
7
Python data types
▪ From the previous example we learn that:
▪ Basic data types, such as integer and float variables
are immutable:
▪ Assigning a new number will not change the value inside
the object by rather create a new one
type: float
y = 5.6
value: 5.6
y = 3
type: int
y
value: 3
8
Python data types
▪ Verify this reasoning with id()
▪ id(my_variable) returns the identifier of the object
that the variable is referencing
my_variable type: int
id: 140735957856544
value: 3
9
Python data types
▪ Jupyter example
▪ Type in your code
In [1]: x = 1
y = x
print(id(x))
print(id(y))
▪ Press CTRL+ENTER to run and obtain a result
Out[1]: 140735957856544
140735957856544
10
Python data types
▪ Basic data types
▪ int, float, bool, str
▪ None
▪ All of these objects are immutable
▪ Composite data types
▪ tuple (immutable list of objects)
▪ list, set, dict (mutable collections of objects)
11
Python data types
▪ int, float
▪ Available operations
▪ +, -, *, /, // (integer division), % reminder, **
(exponentiation)
▪ Example
In [1]: x = 9
y = 5
r1 = x // y # r1 = 1
r2 = x % y # r2 = 4
r3 = x / y # r3 = 1.8
r4 = x ** 2 # r4 = 81
▪ Note that dividing 2 integers yields a float
12
Python data types
▪ bool
▪ Can assume the values True, False
▪ Boolean operators: and, or, not
▪ Example
In [1]: is_sunny = True
is_hot = False
is_rainy = not is_sunny # is_rainy = False
bad_weather = not (is_sunny or is_hot) # bad_weather = False
temperature1 = 30
temperature2 = 35
growing = temperature2 > temperature1 # growing = True
13
Python data types
▪ String
In [1]: string1 = "Python's nice" # with double quotes
string2 = 'He said "yes"' # with single quotes
print(string1)
print(string2)
Out[1]: Python's nice
He said "yes"
▪ Definition with single or double quotes is equivalent
14
Python data types
▪ Conversion between types
▪ Example
In [1]: x = 9.8
y = 4
r1 = int(x) # r1 = 9
r2 = float(y) # r2 = 4.0
r3 = str(x) # r3 = '9.8'
r4 = float("6.7") # r4 = 6.7
r5 = bool("True") # r5 = True
r6 = bool(0) # r6 = False
15
Python data types
▪ Strings: concatenation
▪ Use the + operator
In [1]: string1 = 'Value of '
sensor_id = 'sensor 1.'
print(string1 + sensor_id) # concatenation
val = 0.75
print('Value: ' + str(val)) # float to str
Out[1]: Value of sensor 1.
Value: 0.75
16
Python data types
▪ Working with strings
▪ len: get string length
▪ strip: remove leading and trailing spaces (tabs or
newlines)
▪ upper/lower: convert uppercase/lowercase
In [1]: s1 = ' My string '
length = len(s1) # length = 11
s2 = s1.strip() # s2 = 'My string'
s3 = s1.upper() # s3 = ' MY STRING '
s4 = s1.lower() # s4 = ' my string '
17
Python data types
▪ Sub-strings
▪ str[start:stop]
▪ The start index is included, while stop index is excluded
▪ Index of characters starts from 0
▪ Shortcuts
▪ Omit start if you want to start from the beginning
▪ Omit stop if you want to go until the end of the string
In [1]: s1 = "Hello"
charact = s1[0] # charact = 'H'
s2 = s1[0:3] # s2 = 'Hel'
s3 = s1[1:] # s3 = 'ello'
s4 = s1[:3] # s4 = 'Hell'
18
Python data types
▪ Sub-strings
▪ Negative indices:
▪ count characters from the end
▪ -1 = last character
In [1]: s1 = "MyFile.txt"
s2 = s1[:-1] # s2 = 'MyFile.tx'
s3 = s1[:-2] # s3 = 'MyFile.t'
s4 = s1[-3:] # s4 = 'txt'
19
Python data types
▪ Strings are immutable
In [1]: str1 = "example"
str1[0] = "E" # will cause an error
▪ Use instead:
In [1]: str1 = "example"
str1 = 'E' + str1[1:]
20
Python data types
▪ Formatting strings (from Python 3.6)
▪ Useful pattern to build a string from one or more
variables
▪ E.g. suppose you want to build the string:
var1 var2
My float is 17.5 and my int is 5
▪ Syntax:
▪ f"My float is {var1} and my int is {var2}"
21
Python data types
▪ Formatting strings (older versions)
▪ Syntax:
▪ "My float is %f and my int is %d" % (17.5, 5)
values to be replaced
float placeholder int placeholder
My float is 17.5 and my int is 5
▪ "My float is {0} and my int is {1}".format(17.5, 5)
index of variable that
will replace the braces
22
Python data types
▪ Example (>=Python 3.6)
In [1]: city = 'London'
temp = 19.23456
str1 = f"Temperature in {city} is {temp} degrees."
str2 = f"Temperature with 2 decimals: {temp:.2f}"
str3 = f"Temperature + 10: {temp+10}"
print(str1)
print(str2)
print(str3)
Out[1]: Temperature in London is 19.23456 degrees.
Temperature with 2 decimals: 19.23
Temperature + 10: 29.23456
23
Python data types
▪ None type
▪ Specifies that a reference does not contain data
In [1]: my_var = None
if my_var is None:
print('My_var is empty')
▪ Useful to:
▪ Represent "missing data" in a list or a table
▪ Initialize an empty variable that will be assigned later on
• (e.g. when computing min/max)
24
Python data types
▪ Tuple
▪ Immutable list of variables
▪ Definition:
In [1]: t1 = ('Turin', 'Italy') # City and State
t2 = 'Paris', 'France' # optional parentheses
t3 = ('Rome', 2, 25.6) # can contain different types
t4 = ('London',) # tuple with single element
25
Python data types
▪ Tuple
▪ Assigning a tuple to a set of variables
In [1]: t1 = (2, 4, 6)
a, b, c = t1
print(a) # 2
print(b) # 4
print(c) # 6
26
Python data types
▪ Swapping elements with tuples
In [1]: a = 1
b = 2
a, b = b, a
print(a)
print(b)
Out[1]: 2
1
27
Python data types
▪ Tuple
▪ Tuples can be concatenated
In [1]: t1 = 'a', 'b'
t2 = 2, 4
t3 = t1 + t2
print(t3)
Out[1]: ('a', 'b', 2, 4)
28
Python data types
▪ Tuple
▪ Accessing elements of a tuple
▪ t [start:stop]
In [1]: t1 = ('a', 'b', 'c', 'd')
val1 = t1[0] # val1 = 'a'
t2 = t1[1:] # t2 = ('b', 'c', 'd')
t3 = t1[:-1] # t3 = ('a', 'b', 'c')
t1[0] = 2 # will cause an error
# (a tuple is immutable)
29
Python data types
▪ List
▪ Mutable sequence of heterogeneous elements
▪ Each element is a reference to a Python object
type: list
0 1 2
type: int
type: string value: 3
value: 'my string'
type: float
value: 5.6
30
Python data types
▪ List
▪ Definition
In [1]: l1 = [] # empty list
l2 = [1, 'str', 5.6, None] # can contain different types
a, b, c, d = l2 # can be assigned to variables
# a=1, b='str', c=5.6, d=None
31
Python data types
▪ List
▪ Adding elements and concatenating lists
In [1]: l1 = [2, 4, 6]
l2 = [10, 12]
l1.append(8) # append an element to l1
l3 = l1 + l2 # concatenate 2 lists
print(l1)
print(l3)
Out[1]: [2, 4, 6, 8]
[2, 4, 6, 8, 10, 12]
32
Python data types
▪ List
▪ Other methods:
▪ list1.count(element):
• Number of occurrences of element
▪ list1.extend(l2):
• Extend list1 with another list l2
▪ list1.insert(index, element):
• Insert element at position
▪ list1.pop(index):
• Remove element by position
33
Python data types
▪ List
▪ Accessing elements:
▪ Same syntax as tuples, but this time assigment is allowed
In [1]: l1 = [0, 2, 4, 6]
val1 = l1[0] # val1 = 0
a, b = l1[1:-1] # a=2, b=4
l1[0] = 'a'
print(l1)
Out[1]: ['a', 2, 4, 6]
34
Python data types
▪ List
▪ Accessing elements
▪ Can specify the step
• step = 2 skips 1 element
• step = -1 reads the list in reverse order
• step = -2 reverse order, skip 1 element
In [1]: l1 = [0, 1, 2, 3, 4]
l2 = l1[::2] # l2 = [0, 2, 4]
l3 = l1[::-1] # l3 = [4, 3, 2, 1, 0]
l4 = l1[::-2] # l3 = [4, 2, 0]
35
Python data types
▪ List
▪ Assigning multiple elements
In [1]: l1 = [0, 1, 2, 3, 4]
l1[1:4] = ['a', 'b', 'c'] # l1 = [0, 'a', 'b', 'c', 4]
▪ Removing multiple elements
In [1]: l1 = [0, 1, 2, 3, 4]
del l1[1:-1] # l1 = [0, 4]
36
Python data types
▪ List
▪ Check if element belongs to a list
In [1]: l1 = [0, 1, 2, 3, 4]
myval = 2
if myval in l1:
print("found") # printed because 2 is in list
▪ Iterate over list elements
In [1]: l1 = [0, 1, 2, 3, 4]
for el in l1:
print(el)
37
Python data types
▪ List
▪ Sum, min, max of elements
In [1]: l1 = [0, 1, 2, 3, 4]
min_val = min(l1) # min_val = 0
max_val = max(l1) # max_val = 4
sum_val = sum(l1) # sum_val = 10
▪ Sort list elements
In [1]: l1 = [3, 2, 5, 7]
l2 = sorted(l1) # l2 = [2, 3, 5, 7]
38
Notebook Examples
▪ 1-Python Examples.ipynb
▪ 1) Removing list duplicates
39
Python data types
▪ Set
▪ Unordered collection of unique elements
▪ Definition:
In [1]: s0 = set() # empty set
s1 = {1, 2, 3}
s2 = {3, 3, 'b', 'b'} # s2 = {3, 'b'}
s3 = set([3, 3, 1, 2]) # from list: s3 = {1,2,3}
40
Python data types
▪ Set
▪ Operators between two sets
▪ | (union), & (intersection), - (difference)
In [1]: s1 = {1,2,3}
s2 = {3, 'b'}
s3 = s1 | s2 # union: s3 = {1, 2, 3, 'b'}
s4 = s1 & s2 # intersection: s4 = {3}
s5 = s1 – s2 # difference: s5 = {1, 2}
41
Python data types
▪ Set
▪ Add/remove elements
In [1]: s1 = {1,2,3}
s1.add('4') # s1 = {1, 2, 3, '4'}
s1.remove(3) # s1 = {1, 2, '4'}
42
Python data types
▪ Set
▪ Check if element belongs to a set
In [1]: s1 = set([0, 1, 2, 3, 4])
myval = 2
if myval in s1:
print("found") # printed because 2 is in set
▪ Iterate over set elements
In [1]: s1 = set([0, 1, 2, 3, 4])
for el in s1:
print(el)
43
Python data types
▪ Set example: removing list duplicates
In [1]: input_list = [1, 5, 5, 4, 2, 8, 3, 3]
out_list = list(set(input_list))
print(out_list)
▪ Note: order of elements is not preserved
Out [1]: [1, 2, 3, 4, 5, 8]
44
Python data types
▪ Dictionary
▪ Collection of key-value pairs
▪ Allows fast access of elements by key
▪ Keys are unique
▪ Definition:
In [1]: d1 = {'Name' : 'John', 'Age' : 25}
d0 = {} # empty dictionary
45
Python data types
▪ Dictionary
▪ Access by key:
In [1]: d1 = {'key1' : 'val1', 5 : 6.7}
val1 = d1['key1'] # val1 = 'val1'
val2 = d1[5] # val2 = 6.7
val3 = d1['not_valid'] # Get an error if key does not exist
▪ Reading keys and values:
▪ Note: keys() and values() return views on original data
In [2]: d1 = {'key1' : 1, 'key2' : 2}
keys = list(d1.keys()) # keys = ['key1', 'key2']
values = list(d1.values()) # values = [1, 2]
46
Python data types
▪ Dictionary
▪ Access by key with default value:
In [1]: d1 = {'bottle' : 4, 'glass' : 3}
glass_val = d1.get('glass', 0) # glass_val = 3
bread_val = d1.get('bread', 0) # bread_val = 0
▪ Instead of writing:
In [2]: if 'bread' in d1.keys():
bread_val = d1['bread']
else:
bread_val = 0
47
Python data types
▪ Dictionary
▪ Adding/updating values:
In [1]: d1 = {'key1' : 'val1', 5 : 6.7}
d0['key1'] = 3 # Update existing value
d0['newkey'] = 3 # Add a new key
▪ Deleting a key:
In [2]: d2 = {'key1':1, 'key2':2}
del d2['key1'] # d1 = {'key2':2}
48
Python data types
▪ Dictionary
▪ Iterating keys and values
▪ E.g. get the cumulative cost of items in a market
basket
In [1]: d1 = {'Cola' : 0.99, 'Apples' : 1.5, 'Salt' : 0.4}
cost = 0
for k, v in d1.items():
cost += v
print(f"{k}: {cost}")
Out [1]: Cola: 0.99
Apples: 2.49
Salt: 2.89
49
Controlling program flow
▪ if/elif/else
▪ Conditions expressed with >, <, >=, <=, ==, !=
▪ Can include boolean operators (and, not, or)
In [1]: if sensor_on and temperature == 10:
print("Temperature is 10")
elif sensor_on and 10 < temperature < 20:
in_range = True
print("Temperature is between 10 and 20")
indentation is
else:
mandatory
print("Temperature is out of range or sensor is off.")
50
Controlling program flow
▪ While loop
▪ Iterate while the specified condition is True
In [1]: counter = 0
while counter <5:
print (f"The value of counter is {counter}")
counter += 2 # increment counter of 2
Out [1]: The value of counter is 0
The value of counter is 2
The value of counter is 4
51
Controlling program flow
▪ Iterating for a fixed number of times
▪ Use: range(start, stop)
In [1]: for i in range(5, 8):
txt = f"The value of i is {i}"
print(txt)
Out [1]: The value of i is 5
The value of i is 6
The value of i is 7
52
Controlling program flow
▪ Enumerating list objects
▪ Use: enumerate(my_list)
In [1]: my_list = ['a', 'b', 'c']
for i, element in enumerate(my_list):
print(f"The value of my_list[{i}] is {element}")
Out [1]: The value of my_list[0] is a
The value of my_list[1] is b
The value of my_list[2] is c
53
Controlling program flow
▪ Iterating on multiple lists
▪ Use: zip(list1, list2, ...)
In [1]: my_list1 = ['a', 'b', 'c']
my_list2 = ['A', 'B', 'C']
for el1, el2 in zip(my_list1, my_list2):
print(f"El1: {el1}, el2: {el2}")
Out [1]: El1: a, el2: A
El1: b, el2: B
El1: c, el2: C
54
Notebook Examples
▪ 1-Python Examples.ipynb
▪ 2) Euclidean distance
between lists
55
Controlling program flow
▪ Break/continue
▪ Alter the flow of a for or a while loop
▪ Example
my_file.txt with open("./data/my_file.txt") as f:
car for line in f: # read file line by line
skip if line=='skip':
truck continue # go to next iteration
end elif line=='end':
van break # interrupt loop
print(line)
Out [1]: car
truck
56
Functions
▪ Essential to organize code and avoid
repetitions
parameters
In [1]: def euclidean_distance(x, y):
dist = 0
function name
for x_el, y_el in zip(x, y):
dist += (x_el-y_el)**2
return value return math.sqrt(dist)
invocation print(f"{euclidean_distance([1,2,3], [2,4,5]):.2f}")
print(f"{euclidean_distance([0,2,4], [0,1,6]):.2f}")
Out [1]: 3.00
2.24
57
Functions
▪ Variable scope
▪ Rules to specify the visibility of variables
▪ Local scope
▪ Variables defined inside the function
In [1]: def my_func(x, y):
z = 5 not accessible from outside
return x + y + z
print(my_func(2, 4))
print(z) error: z undefined
58
Functions
▪ Variable scope
▪ Global scope
▪ Variables defined outside the function
In [1]: def my_func(x, y):
return x + y + z z can be read inside the
function
z = 5
my_func(2, 4)
Out [1]: 11
59
Functions
▪ Variable scope
▪ Global scope vs local scope
In [1]: def my_func(x, y):
z = 2 define z in local scope
return x + y + z use z from local scope
z = 5 define z in global scope
print (my_func(2, 4))
print (z) z in global scope is not modified
Out [1]: 8
5
60
Functions
▪ Variable scope
▪ Force the usage of variables in the global scope
In [1]: def my_func(x, y):
global z now z refers to global scope
z = 2 this assigment is performed to z
return x + y + z in the global scope
z = 5
print (my_func(2, 4))
print (z)
Out [1]: 8
2
61
Functions
▪ Functions can return tuples
In [1]: def add_sub(x, y):
return x+y, x-y
sum, diff = add_sub(5, 3)
print(f"Sum is {sum}, difference is {diff}.")
Out [1]: Sum is 8, difference is 2.
62
Functions
▪ Parameters with default value
In [1]: def func(a, b, c='defC', d='defD'):
print(f"{a}, {b}, {c}, {d}")
func(1, 2) # use default for c, d
func(1, 2, 'a') # use default for d, not for c
func(1, 2, d='b') # passing keyword argument
func(b=2, a=1, d='b') # keyword order does not matter
func(1, c='a') # Error: b not specified
Out [1]: 1, 2, defC, defD
1, 2, a, defD
1, 2, defC, b
1, 2, defC, b
63
Lambda functions
▪ Functions that can be defined inline and without
a name
▪ Example of lambda function definition:
input parameter(s) return value
In [1]: squared = lambda x: x**2
print(squared(5))
Out [1]: 25
64
Lambda functions
▪ These patterns are useful shortcuts...
▪ Example: filter negative numbers from a list:
In [1]: numbers = [1, -8, 5, -2, 5]
negative = []
for x in numbers:
if x < 0:
negative.append(x)
▪ This code can be completely rewritten with lambda
functions...
65
Lambda functions
▪ Filter and map patterns
▪ Filter the elements of a list based on a condition
▪ Map each element of a list with a new value
In [1]: numbers = [1, -8, 5, -2, 5]
negative = list(filter(lambda x: x<0, numbers))
squared = list(map(lambda x: x**2, negative))
print(negative)
print(squared)
Out [1]: [-8, -2]
[64, 4]
66
Lambda functions
▪ Lambda functions and conditions
▪ Example conditional mapping:
In [1]: numbers = [1, 1, 2, -2, 1]
sign = list(map(lambda x: '+' if x>0 else '-', numbers))
print(sign)
Out [1]: ['+', '+', '+', '-', '+']
67
List comprehensions
▪ Allow creating lists from other iterables
▪ Useful for implementing the map pattern
▪ Syntax:
iterate all the e.g. list or tuple
elements
In [1]:
res_list = [f(el) for el in iterable]
transform el to
another value
68
List comprehensions
▪ Example: convert to uppercase dictionary keys
▪ (map pattern)
In [1]: dict = {'a':10, 'b':20, 'c':30}
my_list = [str.upper() for str in dict.keys()]
print(my_list)
Out [1]: ['A', 'B', 'C']
69
List comprehensions
▪ Allow specifying conditions on elements
▪ Example: square positive numbers in a list
▪ Filter + map patterns
In [1]: my_list1 = [-1, 4, -2, 6, 3]
my_list2 = [el**2 for el in my_list1 if el>0]
print(my_list2)
Out [1]: [16, 36, 9]
70
List comprehensions
▪ Example: euclidean distance
def euclidean_distance(x, y):
dist = 0
for x_el, y_el in zip(x, y):
dist += (x_el-y_el)**2
return math.sqrt(dist)
def euclidean_distance(x, y):
dist = sum([(x_el-y_el)**2 for x_el, y_el in zip(x, y)])
return math.sqrt(dist)
71
(Dictionary) comprehensions
▪ Similarly to lists, allow building dictionaries
In [1]: keys = ['a','b','c']
values = [-1, 4, -2]
my_dict = {k:v for k, v in zip(keys, values)}
print(my_dict)
Out [1]: {'a': -1, 'b': 4, 'c': -2}
72
List comprehensions
▪ List comprehensions and lambda functions can
shorten your code, but ...
▪ Pay attention to readability!!
▪ Comments are welcome!!
73
Classes
▪ A class is a model that specifies a collection of
▪ attributes (= variables)
▪ methods (that interact with attributes)
▪ a constructor (called to initialize an object)
▪ An object is an instance of a specific class
▪ Example:
▪ class: Triangle (all the triangles have 3 edges)
▪ object: a specific instance of Triangle
74
Classes
▪ Simple class example:
In [1]: class Triangle: class name
num_edges = 3 attribute definition
triangle1 = Triangle() class instantiation
print(triangle1.num_edges) access to attribute
Out [1]: 3
▪ In this example all the object instances of
Triangle have the same attribute value for
num_edges: 3
75
Classes
▪ Constructor and initialization:
In [1]: class Triangle: self is always the
num_edges = 3 first parameter
def __init__(self, a, b, c): constructor
self is a self.a = a parameters
reference to self.b = b initialize attributes
the current self.c = c
object
triangle1 = Triangle(2, 4, 3) invoke constructor
triangle2 = Triangle(2, 5, 2) and instantiate a
new Triangle
76
Classes
▪ Methods
▪ Equivalent to Python functions, but defined
inside a class
▪ The first argument is always self (reference to
current object)
▪ self allows accessing the object attributes
▪ Example:
class MyClass:
def my_method(self, param1, param2):
...
self.attr1 = param1
...
77
Classes
▪ Example with methods
In [1]: class Triangle:
def __init__(self, a, b, c):
self.a, self.b, self.c = a, b, c
def get_perimeter(self): method
use self for return self.a + self.b + self.c
referring to
attributes triangle1 = Triangle(2,4,3)
triangle1.get_perimeter() method invocation
(self is passed to the
method automatically)
Out [1]: 9
78
Classes
▪ Private attributes
▪ Methods or attributes that are available only
inside the object
▪ They are not accessible from outside
▪ Necessary when you need to define elements
that are useful for the class object but must not
be seen/modified from outside
79
Classes
▪ Private attributes
In [1]: class Triangle:
def __init__(self, a, b, c):
self.a, self.b, self.c = a, b, c
2 leading self.__perimeter = a + b + c
underscores def get_perimeter(self):
make variables return self.__perimeter
private
triangle1 = Triangle(2,4,3)
print(triangle1.get_perimeter())
print(triangle1.__perimeter) Error! Cannot access
private attributes
Out [1]: 9
80
Notebook Examples
▪ 1-Python Examples.ipynb
▪ 3) Classes and lambda
functions: rule-based
classifier
81
Exception handling
▪ To track errors during program execution
In [1]: try:
res = my_dict['key1']
res += 1
except:
print("Exception during execution")
In [2]: try:
res = a/b
can specify except ZeroDivisionError:
exception type print("Denominator cannot be 0.")
82
Exception handling
▪ The finally block is executed in any case after try
and except
▪ It tipically contains cleanup operations
▪ Example: reading a file
In [1]: try:
f = open('./my_txt','r') # open a file
... # work with file
except:
print("Exception while reading file")
finally:
f.close()
83
Exception handling
▪ The try/except/finally program in the previous slide
can also be written as follows:
In [1]: try:
with open('./my_txt', 'r') as f:
for line in f:
... # do something with line
except:
print("Exception while reading file")
▪ If there is an exception while reading the file, the
with statement ends
▪ In any case, when the with statement ends the file is
automatically closed (similarly to the finally statement)
84
Notebook Examples
▪ 1-Python Examples.ipynb
▪ 4) Classes and exception
handling: reading csv files
85
Structuring Python programs
▪ The code of a Python project is organized in
packages and modules
▪ Package:
▪ Represented with a directory in the file system
▪ Collects a set of Python modules
▪ A folder must contain a __init__.py file to be
considered a Python package
▪ Module
▪ Represented with a Python file (.py)
▪ Contain attributes, functions and class definitions
86
Structuring Python programs
▪ Example: project structure
MyProject Project main folder
algorithms Package
__init__.py Init file
utils.py
Modules
classifier.py
graphics
__init__.py
charts.py
main_script.py Main script: run with command
python main_script.py
87
Structuring Python programs
▪ Example: content of Python module
graphics charts.py
import matplotlib.pyplot as plt
__init__.py
import os
charts.py
def plot_result():
Function ...
definition plt.plot(...)
...
plot_path = "../Data/plots"
Attribute if not os.path.exists(plot_path):
os.makedirs(plot_path)
Initialization
operations
88
Structuring Python programs
▪ Importing a module
▪ To use attributes, functions and classes defined in a
module, it must be imported with the import
command
graphics main_script.py
import graphics.charts
__init__.py
charts.py
main_script.py
89
Structuring Python programs
▪ Operations executed when importing a module
(e.g. graphics.charts)
▪ Execute __init__.py file in the package
▪ This file can be empty or contain some initialization
instructions for the package
▪ Execute the content of the module (charts.py)
▪ This will load its attributes/functions/classes and run its
initialization code (if any)
graphics
__init__.py
charts.py
90
Structuring Python programs
▪ Operations executed when importing a module
(e.g. graphics.charts)
import graphics.charts
1) Load a function
charts.py
... 2) Load an attribute
def plot_result():
... 3) Initialize directories
plot_path = "../Data/plots"
if not os.path.exists(plot_path):
os.makedirs(plot_path)
91
Structuring Python programs
▪ Importing a module
▪ After import, any attribute, function or class can be
used from the module
main_script.py
import graphics.charts
graphics.charts.plot_result() # Function
print(graphics.charts.plot_path) # Attribute
92
Structuring Python programs
▪ Importing the content of a module
▪ Avoids to write the name of the module when using
attributes or functions
main_script.py
from graphics.charts import *
plot_result() # Function
print(plot_path) # Attribute
93
Structuring Python programs
▪ Other ways of importing modules
▪ Renaming a module
import graphics.charts as ch
ch.plot_result()
▪ Importing a single function/attribute
from graphics.charts import plot_result
plot_result()
94
Structuring Python programs
▪ The main script file(s)
▪ Typically contains a main function
▪ Can also contain functions and classes as any other
module
▪ 2 use cases
▪ Run "python main_script.py" from terminal
• Execute the main function
▪ Import some content (e.g. a function) of the main script
• "from main_script import my_func"
95
Structuring Python programs
▪ The main script file(s)
▪ Use case 1: "python main_script.py"
▪ Python defines a variable called __name__
▪ The if statement is satisfied an main() is called
main_script.py
def main():
print("This is the main function")
if __name__ == '__main__':
main()
96
Structuring Python programs
▪ The main script file(s)
▪ Use case 2: import content to another file
▪ main_script.py is executed by the import, but main() is not
called since __name__ does not contain '__main__'
main_script.py main_script2.py
def my_function(): import main_script
... do something ... main_script.my_function()
...
if __name__ == '__main__':
main()
97