Transcript Python - Dipartimento di Informatica
Python
: Introduzione al linguaggio ed esercizi
Marco Di Felice Sistemi Operativi, AA 2010-2011 Dipartimento di Scienze dell’Informazione Universita ’ degli Studi di Bologna
… Da dove iniziare
Qualche testo consigliato (e reperibile ON-LINE) per iniziare a programmare in Python:
How to think like a Computer Scientist. Learning with Python
– A.Downey, J. Elkner, C. Meyers (GNU)
Dave into Python
– Mark Pilgrim-
Il linguaggio Pyhton
Ideato negli anni ‘80 da G. van Rossum Versione attuale del linguaggio:
2.6
Prevalentemente object-oriented, ma
multi-paradigma
(object-oriented, procedurale, funzionale, etc) Utilizza un
interprete
per l’esecuzione (non compilato) Dispone di
librerie
molto vaste per: parsing (HTML/XML), networking, GUI, accesso a database, Web scripting, etc
Eseguire programmi Pyhton
Due possibili modalita ’ di esecuzione: 1.
Modalita ’
interattiva
$$ python >> a=3+5 1.
Modalita ’
con Program Files
$$ vim myprogram.py
$$ python myprogram.py
Variabili, Tipi, Espressioni
In un programma Python non e’ necessario dichiarare le variabili ed il loro tipo.
Il
tipaggio
avviene
dinamicamente
a run-time.
Assegnamento di valori a a variabili.
message=“Hello world” a=5 x=2.34
>>type(message)
Espressioni
Operatori
matematici
: + - / * // ** % Operatori
logici
: and or not Operatori
di confronto
: >, <, >=, <=
Assegnamento
: = Costanti Booleane: True False Python Costrutti di selezione : if-else / if-elif … - else IF CONDIZIONE: SEQUENZA DI COMANDI RAMO IF ELSE SEQUENZA DI COMANDI RAMO ELSE if x==y: print x, “ and “,y,” are equal “ else print x, “ and “,y,” are different “ Costrutti di iterazione : while WHILE CONDIZIONE: SEQUENZA DI COMANDI DEL CICLO X=1.0 while x<10.0: print x,” “,math.log(x) x=x + 1.0 Python utilizza l’ indentazione graffe) per distinguere (e non le parentesi l’inizio e la fine di un blocco (es. Il codice da eseguire all’interno di un ciclo). Per questo motivo, indentare bene il codice e’ fondamentale! while n>0: n=n-1 print n DIVERSO!! while n>0: n=n-1 print n Keyword def per identificare l’inizio di una funzione DEF nomeFUNZIONE (argomenti): CORPO della FUNZIONE RETURN valore (opzionale) Per richiamare una funzione: nomeFUNZIONE (argomenti) Python consente di definire al volo piccole funzioni in una sola riga ( lambda -funzioni). >> g= lamdba x: x**2 >> g(4) >> 16 • Le funzioni lambda non possono contenere comandi e non possono contenere piu ’ di un’espressione ( ES1 ): Scrivere il codice della funzione fattoriale: ( ES1 ): Scrivere il codice della funzione fattoriale: # Factorial function def factorial(n): if (n==0): return 1 else return n*factorial(n-1) >> print factorial(4) >> 24 Python consente di definire funzioni con parametri opzionali ; se la funzione e’ chiamata senza argomento, l’argomento prende il valore predefinito (indicato nella signature della funzione). def power(a,b=2): return a**b >> power(4,3) >> power(4) In Python, una stringa e’ una lista di caratteri. message=“Hello world” La funzione len restituisce la lunghezza >> len(message) >> 11 L’operatore [] consente di accedere ai singoli caratteri che compongono la stringa: >> print message[0] >> ‘H’ >> message=“Hello world” >> print message [0] >> ‘H’ >> print message [2:3] >> ‘l’ (Seleziona una sottostringa) >> print message [2:] >> ‘llo World’ (Seleziona una sottostringa) >> print message [-1] >> ‘d’ Le stringhe sono liste IMMUTABILI . message[0]=‘G’ NON SI PUO’ FARE!! Libreria di funzioni su stringhe import string Liste predefinite della classe string: string.lowercase string.uppercase String.digits L’operatore for … in consente di ciclare su tutti gli elementi di una lista for c in str: print c L’operatore in verifica la presenza di un carattere in una stringa. if c in str: print “Found!” ( ES2 ): Scrivere una funzione check_string(str) che riceve in input una stringa, e ritorna 0 se la stringa str e ben formata, 1 altrimenti. Assumiamo che una stringa sia ben formata se contiene solo caratteri minuscoli. import string def check_string(str): for c in str: if not(c in string.lowercase): return 0 return 1 >> print check_string (“hello), “ “, check_string(“Hello”) >> 1 0 In Python, una lista cui ciascun valore e’ un insieme ordinato di valori, in e’ identificato da un indice. [] LISTA VUOTA [1,2,3,4,5] [“Hello”, “World”, “Python”] Gli elementi possono essere eterogenei: [“Hello”,1,3.4,5] [“Hello”, [1,2], 4, 10, [1,2,3]] Come con le stringhe: [] per accedere ad un elemento della lista in verifica la presenza di un elemento in una lista len restituisce la lunghezza della lista + concatena due liste * ripete una lista un dato numero di volte A differenza delle stringhe, le liste sono MUTABILI a=[1,2,3,4], a[0]=-1 del per rimuovere un elemento della lista del a[0] append aggiunge un elemento alla lista (in fondo) insert aggiunge un elemento in una posizione specifica a.append(6) a.insert(0,6) Le liste sono passate per riferimento e non per valore. a=[1,2,3] b=a a a [1,2,3] [1,2,3] • … E se invece b=a[:] ?? ( ES3 ) Data la lista seguente: a=[[1,2],3,4,5,6] Definire quali delle operazioni sono valide e quali no. a[0][0]=5 print a[0][-3] print a[0][-1] a[5]=‘b’ a[2:4]=[2] ( ES4 ) Determinare l’output del programma seguente: a=[‘a’,’b’,[‘b’,’c’],1,2,3] del a[0] a[1][0]=‘a’ c=a[2:4] d=a[1] e=c+d print e ( ES5 ) Determinare l’output del programma seguente: def fun(a): return a[2:] a=[1,2,3,4,5] b=a b[3]=6 c=fun(a) c[2]=3 print c ( ES6 ) Scrivere un programma che legge input 5 numeri interi da tastiera. Ogni numero letto viene inserito in una lista solo se non e’ un duplicato di un numero gia ’ letto. Se e’ un duplicato, il programma continua la lettura da tastiera finche ’ un numero non duplicato viene digitato. Dopo aver letto i 5 valori, il programma ne calcola la media e la stampa a video. # Read an integer value from the keybord def read_number(): message="Please insert an integer value " read=input(message) return read # Returns a list of 5 non-replicated values def read_list_values(): listread=[] # Number of readings from the input numread=0 while (numread <5): val=read_number() # Check if the reading is valid if not (val in listread): listread.append(val) numread+=1 else: print "This is a duplicated value ..." return listread # Main program listv=read_list_values() # Initialize the average value average=0.0 # Compute the average value for val in listv: average+=val average=average / len(listv) print " The average value is ...", average List comprehension => Tecnica compatta per mappare una lista in un’altra applicando una funzione a ciascuno degli elementi della lista. >> li=[1,2,3,4,5] >> li2=[elem * 4 for elem in li] >> print li2 >> [4,8,12,16,20] List comprehension + Filtri => E’ possibile aggiungere dei filtri, in modo che alcuni elementi vengano mappati ed altri restino alterati. >> li=[1,2,3,4,5] >> li2=[elem * 4 for elem in li if elem >2 ] >> print li2 >> [12,16,20] ( ES7 ) Scrivere una funzione check_sum_present(li, value) che prende in input una lista di interi (si assume senza elementi duplicati) ed un valore e verifica se nella lista ci sono due elementi a,b tali che a+b=value . La funzione deve restituire la lista di tutte le coppie [a,b] che soddisfano la condizione. def check_sum_present(li, value): return [ [elem,value-elem] for elem in li if (((value-elem) in li) and (value elem !=elem )) ] li=[1,2,3,4,5,6,7,8] print check_sum_present(li,11) Una tupla di elementi differenza delle liste e’ simile ad una lista, ma a e’ IMMUTABILE . tuple=1,2,3,4,5 tuple=(‘a’,’b’,’c’,’d’,’e’) Le tuple sono utili per fare swap di variabili o assegnamenti multipli: y, x = x, y a, b, c, d = 1, ‘Hello’, 4, 5.6 A che servono le tuple? Le tuple sono piu ’ veloci delle liste => utilizzare le tuple nel caso in cui si debba solo iterare su un insieme di valori e non si debba modificarli. Consentono di proteggere dalla scrittura i dati che non devono essere modificati. Le tuple, a differenza delle liste, possono essere usate come chiavi di un dizionario . Un dizionario e’ un insieme di coppie: dict={} dict[‘Mario’]=“0861343242” dict[‘Monica’]=“086243434” dict{‘Mario’:’0861343242’, ‘Monica’: …} Il metodo len restituisce il numero di elementi Il metodo keys resistuisce la lista delle chiavi Il metodo values restituisce la lista dei valori Il metodo del elimina un elemento dalla lista Il metodo clear cancella tutto il contenuto di un dizionario >> print dict.keys() >> print dict.values() >> del dict[2] Il metodo get restituisce il valore associato ad una certa chiave: >> print dict.get(“Mario”) >> print dict.get(“Mario”,”Nome non trovato”) • Il metodo has_key ritorna 1 se la chiave appare nel dizionario, 0 altrimenti. >> print dict.has_key(“Mario”) >> True Non possono esserci duplicazioni di chiavi in un dizionario. Gli elementi di un dizionario NON sono ordinati. Valori e chiavi possono assumere qualsiasi tipo. Non necessariamente tutte le chiavi devono avere lo stesso tipo. dict={“0”:120,”Marco”:32,”1.0”:[1,2,3]} ( ES8 ) Scrivere un programma che calcola il prodotto di due matrici (supponiamo entrambe le matrici abbiano dimensione NxN) ( ES9 ) Ottimizzare il programma precedente nel caso in cui le matrici siano sparse (cioe ’ gran parte dei valori delle matrici siano settati a 0) ( ES10 ) Indicare l’output del programma seguente. str=“hello” dict={‘h’:1,’e’:2,’l’:3} val=0 for c in str: val=val+dict.get(c,-1) print val ( ES11 ) Indicare l’output del programma seguente. def fun(d,x): if d.has_key(x): d[x]=3 dic={‘a’:1,’b’:2,’c’:4} dic2=dic.copy() dic3=dic del dic[‘a’] fun(dic2,’a’) fun(dic3,’a’) dic2[‘b’]=dic2[‘a’]+dic3.get(‘a’,-2) print dic2[‘b’] Python e’ un linguaggio ad oggetti ; l’astrazione di classi ed oggetto ha molti punti in comune con altri linguaggi di programmazione (es. Java) class Point: def __init__(self,x=0,y=0): self.x=x self.y=y Il metodo __init__ e’ Il costruttore della classe. self e’ il riferimento all’oggetto corrente, tramite il quale si puo’ accedere ad i campi dell’oggetto corrente. E’ il primo parametro di ogni metodo della classe, ma non deve essere passato dal chiamante. class Point: def distance(self, other): … p= Point(10,20) p1=Point(20,30) p.distance(p1) => NON: p.distance(p,p1)!! Come in altri linguaggi ad oggetti , e’ possibile fare overloading di operatori built-in (es. addizione, moltiplicazione, sottrazione, etc) def __add__(self, other): return Point(self.x+other.x,self.y+other.y) Point p1=new Point(x1,y1) Point p2=new Point(x2,y2) p3=p1 + p2 Come in altri linguaggi ad oggetti , e’ possibile creare gerarchie di classe tramite l’ereditarieta’. Come C++, Python supporta l’ereditarieta’ multipla. Per indicare che la classe Point3D e’ figlia della classe Point : class Point3D(Point): Esistono alcuni metodi di classe “speciali”: • __repr__ ritorna una rappresentazione di un oggetto sotto forma di una stringa • __cmp__ e’ utilizzato quando si effettua il confronto tra classi (overloading dell’operatore ==) • __len__ ritorna la lunghezza dell’oggetto • __delitem__ richiamato da del istanza[chiave] E’ possibile definire metodi privati che non possono essere referenziati all’esterno della classe. La distinzione tra metodi pubblici e metodi privati si basa esclusivamente sul nome. Se il nome di un metodo o attributo inizia con (man non finisce con) due underscore, e’ privato; ogni altra cosa e’ pubblica. def __myfunction(): Come in Java/C++, Python consente la manipolazione delle eccezioni tramite I blocchi try…except Il comando raise viene usato per lanciare un’eccezione. try: fsock=open(“file.dat”,”r”) except IOError: ( ES12 ) Indicare l’output del programma seguente. import copy class Obj: pass def fun(p): p2=copy.copy(p) if (p2.b==7): p2.b=10 p=Obj() p.a=5 p.b=7 p2=p p2.b=5 p3=fun(p) print p2.a=4 return p2 ( ES13 ) Implementare una classe con I metodi , e class Stack: # Class initializer def __init__(self): self.values=[] # Push a value on top of the stack def push(self,value): self.values.append(value) # Return the value on top def pop(self): if len(self.values) > 0: return self.values.pop() else: raise ValueError # Check if there are elements in the stack def is_empty(self): return (len(self.values) == 0) Tutti I tipi di sequenza incorporati in Python supportano gli iteratori tramite ciclo for. for value in sequence: DO SOMETHING E’ possibile costruire degli iteratori su classi arbitrarie definendo I seguenti metodi: - __iter__(): restituisce l’oggetto iteratore - next(): restituisce l’elemento successivo ( ES14 ) Implementare che la classe consente definire delle liste circolari in Python. di # Implements a Circular Queue class CircularQueue: def __init__(self,values): self.values=values def __iter__self(self): return self # Iterator function def next(self): if (len(self.values) > 0): self.values=self.values[1:] + [self.values[0]] return self.values[-1] else: raise ValError ( ES15 ) Implementare la classe che consente di costruire degli alberi (generici). Definire un iteratore della classe che consente di fare visite in profondita ’ dell’albero. Un iteratore puo ’ essere utilizzato per generare sequenze di valori. Un valore viene prodotto su richiesta quando necessario. La sequenza di valori puo ’ essere infinita. ( ES16 ) Definire tramite iteratori la classe Factorial che costruisce la sequenza dei fattoriali 1!, 2!, 3!, 4! … etc class Factorial: def __init__(self): self.fact=0 self.val=1 def __iter__(self): return self def next(self): (self.val,self.fact,oldval)=(self.val*(self.fact+1),self.fact+1, self.val) return oldval for i in Factorial(): print i if i>30: break Un generatore e’ un’entita che genera iteratori. Un generatore e’ una funzione che si richiama ripetutamente: ogni volta che viene richiamata, l’esecuzione non ricomincia da capo, ma dal punto di codice in cui la precedente chiamata ha restituito un valore. Il comando yeld specifica il punto in cui un generatore deve ritornare un valore. ( ES17 ) Indicare l’output del programma seguente. def gen(): val=2 while: yeld val val=val*2 count=0 for i in gen(): if (count >=10): break else: print i count+=1 ( ES18 ) Scrivere una funzione generatrice di numeri primi (usando i generatori di Python). def prime_num(): n=2 prime=[] while True: if not[f for f in prime if n%f ==0]: yield n prime.append(n) n=n+1 # Print out all the prime numbers <100 for i in prime_num(): if (i> 100): break print i ( ES19 ) Scrivere una funzione permutation(li) che genera tutte le possibili permutazioni di una lista presa in input >> permutation([1,2,3]) >> [[1,2,3],[1,3,2],[2,3,1][2,1,3],[3,1,2],[3,2,1]] def permutation(list): if len(list)<=1: yield list else: for i in range(0,len(list)): for tail in permutation(list[:i] + list[i+1:]): yield [list[i]] + tail for i in permutation([1,2,3,4]): print i ( ES20 ) Scrivere una funzione powerset(li) che prende in input una lista e stampa tutti i possibili sottoinsiemi della lista (insieme potenza). >> power_set([1,2,3]) >> [[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]] def powerset(li): if len(li) <=1: yield li yield [] else: for item in powerset(l[1:]): yield [li[0]] + item yield item for i in powerset([1,2,3]): print i Il modulo os dispone di molte funzioni utili per manipolare file e processi. listdir(path) ritorna il contenuto di una directory (in una lista). chdir(path) cambia la directory corrente a path chmod, chown, mkdir, rmdir, getcwd(), mknod () … getlogin(), getpid(), getuid(), getppid (), … Il modulo os dispone di molte funzioni utili per manipolare file e processi. import os print "Current directory is ",os.getcwd() print "Current login is ",os.getlogin() print "Current Process id is ",os.getpid() ( ES21 ) Scrivere un programma che fa scanning della rete, nel range di indirizzi da 192.168.100.60 a 192.168.100.70. A ciascuna macchina della rete devono essere inviati 2 pacchetti ping, ed in base all’esito del comando il programma deve visualizzare il messaggio: “No response” o “Alive”. import os import re import time import sys lifeline = re.compile(r"(\d) received") report = ("No response","Partial Response","Alive") print time.ctime() for host in range(60,70): ip = "192.168.100."+str(host) pingaling = os.popen("ping -q -c2 "+ip,"r") print "Testing ",ip, sys.stdout.flush() while 1: line = pingaling.readline() if not line: break igot = re.findall(lifeline,line) if igot: print report[int(igot[0])] print time.ctime() Il modulo socket implementa i costrutti principali per la programmazione di rete tramite socket (C-like). socket(family,type) crea un nuovo socket family: AF_UNIX, AF_INET, AF_INET6 type: SOCK_STREAM (tcp), SOCK_DGRAM(udp) bind(host, port) : collega il socket ad un host name e ad una porta specificata accept() : accetta connessioni da un client. Restituisce: (nuovo socket per comunicare con il client, indirizzo del client) send(), recv() : inviano/ricevono dati close() : chiude il socket ( ES22 ) Scrivere una semplice applicazione di rete Client-Server. Il client resta in attesa di ricevere un messaggio da tastiera e lo spedisce al Server, che lo stampa a video. import socket class SocketClient: def __init__(self,host, port): size=1024 while True: message="Insert a message to send " read=raw_input(message) s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((host, port)) s.send(read) s.close() message="Insert Q to exit … " read=raw_input(message) if (read == "Q"): break sc=SocketClient("localhost",5000) import socket class ServerSocket: def __init__(self): self.host="localhost" self.port=5000 self.size=1024 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind((self.host,self.port)) s.listen(5) while True: client, address = s.accept() data = client.recv(self.size) print " [SERVER ECHO] Receiving data from ",address," Message: ",data client.close() ss=ServerSocket() select(input, output, exception, [timeout]) : gli argomenti sono liste di socket che attendono per input/output/eccezioni. La chiamata della select e’ bloccante se timeout non e’ impostato Ritorna una tupla di tre liste: sottoinsieme dei socket in input che hanno input/output/eccezioni. ( ES23 ) Modificare la configurazione del Server dell’esercizio ES21 in modo che sia in grado di gestire piu ’ connessioni in ingresso dai Client tramite la select. class ServerSocket: def __init__(self): self.host="localhost" self.port=5000 self.size=1024 server=socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind((self.host,self.port)) server.listen(5) input= [server] while True: inputready,outputready,exceptionready= select.select(input,[],[]) for c in inputread: if (c==server): client, address = server.accept() input.append(client) else: data = c.recv(self.size) c.close() input.remove(c) TWISTED : framework per il networking che consente di sviluppare applicazioni di rete in Python Consente di creare: protocolli di rete, SMTP, HTTP, SSH proxy, filtri di traffico, etc http://twistedmatrix.com/ Il modulo threading offre una libreria di funzioni per lavorare con i thread. Per creare un thread, occorre creare una classe figlia di threading.Thread . Per avviare il thread, occorre eseguire il metodo start. Il codice del thread e’ contenuto nel run. Thread diversi potrebbero avere necessita ’ di condividere strutture dati. METODO 1. => utilizzo del modulo Queue Implementa lock e metodi synchronized per l’accesso a strutture condivise. Metodi: get , put , join , task_done , … ( ES24 ) Modificare l’esercizio E20 in modo da suddividere l’operazione di scansione della rete tra N thread. import os import re import time import sys import Queue import threading lifeline = re.compile(r"(\d) received") report = ("No response","Partial Response","Alive") print time.ctime() queue=Queue.Queue() class ThreadScanner(threading.Thread): def __init__(self, queue): threading.Thread.__init__(self) self.queue = queue def run(self): while True: host = self.queue.get() ip = "192.168.100."+str(host) pingaling = os.popen("ping -q -c2 "+ip,"r") print "Testing ",ip, sys.stdout.flush() while 1: line = pingaling.readline() if not line: break igot = re.findall(lifeline,line) if igot: print report[int(igot[0])] self.queue.task_done() # List of Threads for i in range(0,5): t=ThreadScanner(queue) t.start() for host in range(60,70): queue.put(host) queue.join() print time.ctime() Oltre al modulo Queue , Python mette a disposizione i tradizionali sincronizzazione per meccanismi di l’accesso a strutture dati condivise: Lock : metodi acquire – release Re-Entrant Lock ( RLocks ) SemaforiCostrutti di selezione
Costrutti di iterazione
Indentazione e Blocchi
Dichiarazione di Funzioni
Funzioni Lambda
Dichiarazione di Funzioni
Dichiarazione di Funzioni
Parametri e Funzioni
Operazioni su Stringhe
Operazioni su Stringhe
Operazioni su Stringhe
Operazioni su Stringhe
Operazioni su Stringhe
Operazioni su Stringhe
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Liste di Elementi
Tupla di Elementi
Tupla di Elementi
Dizionari
Dizionari
Dizionari
Dizionari
Dizionari
Dizionari
Dizionari
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Classi ed Oggetti
Stack
push
pop
is_empty.
Classi ed Oggetti
Iteratori
Iteratori
CircularQueue
Iteratori
Iteratori
Tree
Iteratori
Iteratori
Generatori
Generatori
Generatori
Generatori
Generatori
Generatori
Generatori
Generatori
Moduli e Librerie
Moduli e Librerie
Moduli e Librerie
Moduli e Librerie
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Programmazione di Rete
Thread
Thread
Thread
Thread
Thread
Thread
Thread