Edit this page Backlinks This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== 1. Introduction to Python ====== Python3 is a multi-paradigm language, that combines the **imperative** style with the **functional** style. It also supports Object-Oriented programming, albeit in a limited way. Python3 offers a few programming constructs that: * make life real easy for the programmer, * yield efficient programs, * sum-up to a programming **style** called **pythonic** (a blend of imperative and functional features). This lab will introduce some of these constructs. ==== List traversal ==== **Exercise 1.1.** Write a function ''f(l)'' which determines the maximum of a list ''l'' of integers. <hidden The pythonic way> Traversing a list using a ''for'' is done as follows: <code python> for elem in collection: # do something </code> This idiom can be used for any collection not just lists, as you will discover during the lab. </hidden> **Exercise 1.2.** Modify the previous function to ''f(l,start,stop)'' and determine the maximum between positions ''start'' and ''stop''. <hidden The pythonic way> When we care about the indices of a list, we can use the function ''range(x,y)'' which returns **a list of integers** starting from ''x'' until ''y-1''. <code python> for i in range(0,len(collection)): # do something with collection[i] </code> </hidden> ==== Slicing lists ==== **Exercise 1.3.** Find the **longest** sequence of positive integers from a list. E.g. for the list ''[1,3,-1,2,0,1,5,4,-2,4,5,-3,0,1,2]'' the answer is ''[2,0,1,5,4]''. <hidden The pythonic way> Python supports various list slicing operations, as well as "overloaded" indexing: <code python> # the sublist from positions 0 to x of l: l[0:x] # the very same list: l[:x] # the last element of a list: l[:-1] # the last three elements of a list: l[:-3] # the slice from n-3 to n-1, where n is the number of elements from the list l[-3:-1] </code> </hidden> **Exercise 1.4.** Write a pythonic function to check if a list is palindrome. ===== Other datatypes ===== The most widely used datatypes in Python are lists and dictionaries. Additionally, at LFA, we will also use: **sets**, **stacks**. ==== Stacks ==== In Python, **lists** are also used as stacks: <code python> l = [] l.append(x) # add x at the TOP of the stack (this will be the last element of the list) l[-1] # this is the top of the stack x = l.pop() # removes and returns an element from the top of the stack. </code> **Exercise 1.5.** Write a function which determines (and returns) the **longest** sequence of consecutive integers from a list. ==== Dictionaries ==== Python dictionaries are actually **hash maps** (or **hash tables**). The keys ''k'' are **dispersed** using a hash-function into buckets. Each bucket will hold its respective values. Some examples of dictionary usage: <code python> #create an empty dictionary: d = {} #add or modify a key-value: d[k]=v #search if a key k is defined in a dictionary d: if k in d: # do something </code> **Exercise 1.6.** Write a function which determines the number of occurrences of each character in a string. <hidden The pythonic way> <code python> def count(l): d = {} for x in l: if x in d: d[x] += 1 else: d[x] = 1 return d </code> </hidden> ==== Sets ==== Sets are collections where each element is unique. Sets can be traversed and indexed exactly as lists. They are initialised using the constructor ''set'': <code python> # the empty set: s = set() # set constructed from a list: s = set([1,2,3]) # adding a new element to the set: s.add(4) </code> **Exercise 1.7.** Determine the list of characters which occur in a string. E.g. for "limbajeformale" we have: "limbajefor". (Hint 1: in Python there is no difference between a character and a singleton string and strings are just lists; Hint 2: to create a list from another object, use ''list()''). ==== Pairs ==== Pairs are very similar to lists and can be substituted by the latter in many cases: <code python> p = (x, y) # a pair where the first element is x and the second is y t = (x, y, z) # a tuple fst = p[0] snd = p[1] for k in t: # do something with element k of the tuple </code> ===== The functional style ===== ==== Higher-order functions and lambdas ==== The most used higher-order functions in Python are **map** and **reduce**: <code python> from functools import reduce # adds 1 to each element of a list def allplus1(l): return map(lambda x:x+1,l) # computes the sum of elements of a list def sum_l (l): # inner functions are very useful for defining local, reusable functionality def plus(x,y): return x + y return reduce(plus,l) # reduce is a little different from Haskell folds: it does not use an initial value def short_sum(l): return reduce(lambda x,y:x+y,l) # observe the syntax for lambdas </code> ==== List comprehensions ==== List comprehensions are widely used programming tools in Python. Usage examples: <code python> # adding 1 to each element of a list l1 = [x+1 for x in [1,2,3]] # [2,3,4] # packing elements into pairs l2 = [(x,x+1) for x in [1,2,3]] # [(1,2), (2,3), (3,4)] # unpacking pairs in the for notation l3 = [x+y for (x,y) in [(1,2), (2,3), (3,4)]] # [3,5,7] # combined list comprehensions l4 = [(x,y) for x in [1,2,3] for y in [4,5,6]] # [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)] # filters l5 = [x for x in [1,2,3,4] if x>2] # [3,4] </code> **Exercise 1.8.** Write a function which takes a list of records //first name, last name, CNP// (encoded as tuples), and returns a list of **the last names** and **ages** of all females which are younger than the average of the entire list. E.g. ''[ ("Mary", "Smith", "2030602123456"), ("Anne", "Doe", "2121092123456"), ("Matei", "Dan", "1121202123456"), ("Maggie", "Byrne", "2121078123456")]'' yields ''[("Smith",19), ("Doe",29)]''. Maggie was born in '78, whereas Mary, Anne and Matei were born in '94, '92 and 2002, respectively. <hidden The pythonic way> <code python> from functools import reduce def getYouth(l): # this function computes the age of a given CNP def age(cnp): # conversion to integer of the two-character year code if int(cnp[5:8]) <= 21: return 2021 - int("20"+cnp[5:7]) else: return 2021 - int("19"+cnp[5:7]) # computing the average ages (a map could have also been used) avg = reduce(lambda a,b:a+b, [age(x) for x in l]) / len(l) # we return the last name and the age of the filtered list l return [(ln,age(cnp)) for (fn,ln,cnp) in l if cnp[0]=='2' and age(cnp) <= avg] </code> </hidden> /* ==== Classes and inheritance ==== We discuss a few basics on classes and inheritance starting from the following example: <code python> class Tree: def size(self): pass def contains(self, key): pass class Void(Tree): def __init__(self): pass def __str__(self): return "Nil" def size(self): return 0 def contains(self,key): return False </code> In the previous example, the class ''Tree'' acts as an interface. Python does not natively support interfaces, but class inheritance is supported. The instruction ''pass'' does nothing, and it helps us defer the method implementation. The definition: <code python> class Void(Tree) </code> tells us that class ''Void'' inherits ''Tree''. Note that this //contract// is not binding in Python. The program will be interpreted even if ''Void'' does not correctly implement the methods in ''Tree''. The function <code python> def __init__(self): </code> is the class constructor. We cannot explicitly define multiple constructors (but workarounds exist). Also note the mandatory presence of ''self'', which is the Python equivalent of ''this''. Each member class must mark as first argument ''self'', otherwise it is not a proper member of the class, and just a nested function. The function <code python> def __str__(self): </code> is the Python equivalent for ''toString()''. An object can be displayed using the function ''str'' **Exercise 9** Create the class ''Node'' which models non-empty trees. Implement methods ''size'' and ''contains''. ==== List of exercises ==== * Write a function which prints EACH repeating character from a string. (Hint: strings are lists of characters). * Write a function returns the number of repetitions of each character from a text. (Hint: use dictionaries to store the number of repetitions). * Write a function returns the number of unique characters from a list. Use Python sets. * Write a function which takes a pattern and a text and prints all indexes where an occurrence of pattern in text are found. Use Python list slicing. * Write a function which searches for a list of patterns in a text, by extending the stub below. Whenever possible, use ''map'' instead of ''for''. <code python> def find_patterns (pattern_list, text): # checks if pattern is found at position index in text def inner_search (pattern,index): </code> * Extend the class example shown previously to include class ''Node'' which models non-empty trees. Implement methods ''size'' and ''contains''. */ ===== Practice ===== A labelled graph is encoded as a file where: * **the first line** consists of the number of nodes * **each subsequent line** is an edge ''<from> <label> <to>'' Example: <code> 4 0 X 1 1 O 2 1 X 3 1 O 4 4 X 1 3 O 2 </code> * Suppose we encode streets as labelled graphs, where each label 'X' or 'O' denotes if a street is closed or open. * Compute the set of accessible nodes from a given **source**, via open streets. * (Hint1: google //Python read lines// to see how to read from a file; also, google ''split'' in Python) * (Hint2: you will need a dictionary to store, for each node and label l, the list of its l-successors) ===== Haskell practice ===== Solve the same exercise, only build your own input as a string, instead of a file.