• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Pyimproved
 

Pyimproved

on

  • 389 views

Object Oriented programming in Python.

Object Oriented programming in Python.

Originally part 2 of a 4 lectures seminar for the Networking class of the Computer Science course at the University of Parma

Statistics

Views

Total Views
389
Views on SlideShare
383
Embed Views
6

Actions

Likes
0
Downloads
0
Comments
0

1 Embed 6

http://www.linkedin.com 6

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Pyimproved Pyimproved Presentation Transcript

  • Approfondimenti suPythonEnrico Franchienrico.franchi@gmail.comfranchi@cs.unipr.it
  • DOMANDE?
  • RIGIDO OFLESSIBILE?
  • CAMBIARE LEFONDAMENTA?
  • Espressioni regolari(PCRE) Modulo re re.compile: compila l’espressione regolare R.match, R.find, R.findall, R.finditer M.group, M.groups ... Utili e potenti, basta non abusare Usare se possibile la sintassi estesa con commenti
  • Docstringdef read_all(name_or_handle): Read the whole content of specified file. name_or_handle can be a readable file-like object or a filename. In the latter case, the file is opened and the contents are returned. try: return name_or_handle.read() except AttributeError: handle = open(name_or_handle) try: return handle.read() finally: handle.close()
  • Docstringdef read_all(name_or_handle): Read the whole content of specified file. name_or_handle can be a readable file-like object or a filename. In the latter case, the file is opened and the contents are returned. try: return name_or_handle.read() except AttributeError: handle = open(name_or_handle) try: return handle.read() finally: handle.close() Legge tutto il contenuto, nel modo più efficiente
  • Docstringdef read_all(name_or_handle): Attenzione! Secontent of specified file. handle dentro al try e Read the whole proviamo a legare name_or_handle can be a readable file-like objectabbiamo un’eccezione, handle.close viene provato su un or a filename. In the latter case, the file is opened and the contents are returned. a questo livello non handle ancora unbound. Inoltre try: sapremmo gestire un IOError return name_or_handle.read() except AttributeError: handle = open(name_or_handle) try: return handle.read() finally: handle.close() Legge tutto il contenuto, nel modo più efficiente
  • Docstring (2) La prima cosa nel corpo della funzione é una stringa. In questo caso é detta “docstring” Si applica anche a classi e moduli Quella stringa diventa documentazione della funzione (internamente è legata con l’attributo __doc__)
  • Docstring (2) La prima cosa nel corpo della funzione é una stringa. In questo caso é detta “docstring” Si applica anche a classi e moduli Quella stringa diventa documentazione della funzione (internamente è legata con l’attributo __doc__) >>> import example_docstring >>> help(example_docstring.read_all)
  • Docstring (2) La prima cosa nel corpo della funzione é una stringa. In questo caso é detta “docstring” Si applica anche a classi e moduli Quella stringa diventa documentazione della funzione (internamente è legata con l’attributo __doc__) >>> import example_docstring >>> help(example_docstring.read_all) read_all(name_or_handle) Read the whole content of specified file. name_or_handle can be a readable file-like object or a filename. In the latter case, the file is opened and the contents are returned.
  • Named parametersConsiderate questa versione di read_all L’utente specifica il nome di file o l’handle di file def read_all(filename=None, handle=None): Read the whole content of specified file. if handle: return handle.read() elif filename: handle = open(filename) try: return handle.read() finally: handle.close() raise TypeError, read_all takes one argument
  • Named parametersConsiderate questa versione di read_all L’utente specifica il nome di file o l’handle di file def read_all(filename=None, handle=None): Read the whole content of specified file. if handle: return handle.read() elif filename: handle = open(filename) try: return handle.read() finally: handle.close() raise TypeError, read_all takes one argument >>> improved_read_all.read_all(improved_read_all.py) >>> improved_read_all.read_all(filename=improved_read_all.py) >>> improved_read_all.read_all(handle=open(improved_read_all.py))
  • Aprire un file Il tipico modo di aprire un file é usare la funzione open oppure il costruttore degli oggetti file (file) open é praticamente un alias per file file(name[, mode[, buff]]) -> file object Mode è una stringa che indica come il file deve essere aperto: lettura, scrittura, append, binario, text buff controlla il buffering
  • Modi di apertura Descrizione r [Default] : Aperto in sola lettura, deve esisterew Aperto in sola scrittura, troncato e sovrascritto a Aperto in sola scrittura, si appende in fondor+ Deve esistere, aperto lettura e scritturaw+ Troncato se esiste, aperto lett. e scritt.a+ Aperto in lettura e scrittura, appende t [Default] : su Win ritorna n quando trova il separatoreb Restituisce esattamente quello che trovaU Restituisce ‘n’ qualunque separatore trovi
  • Apriamo in lettura...file_object = open(thefile.txt)try: for line in file_object: # process line # maybe: # print line.rstrip() passfinally: file_object.close()
  • Apriamo in lettura...file_object = open(thefile.txt)try: for line in file_object: # process line # maybe: # print line.rstrip() passfinally: file_object.close() chunk_size = 256 file_object = open(binary_file.dat, rb) try: while True: chunk = file_object.read(256) if not chunk: break # process chunk... finally: file_object.close()
  • Apriamo in lettura... F.readlines() -> una lista di stringhe chunk_size = 256file_object = open(thefile.txt) file_object = open(binary_file.dat, rb)try: try: for line in file_object: while True: # process line chunk = file_object.read(256) # maybe: if not chunk: # print line.rstrip() break pass # process chunk...finally: finally: file_object.close() file_object.close()
  • Apriamo in lettura... F.readlines() -> una lista di stringhe F.xreadlines() -> iteratore di stringhe chunk_size = 256file_object = open(thefile.txt) file_object = open(binary_file.dat, rb)try: try: for line in file_object: while True: # process line chunk = file_object.read(256) # maybe: if not chunk: # print line.rstrip() break pass # process chunk...finally: finally: file_object.close() file_object.close()
  • Apriamo in lettura... F.readlines() -> una lista di stringhe F.xreadlines() -> iteratore di stringhe F.readline() -> una linea chunk_size = 256file_object = open(thefile.txt) file_object = open(binary_file.dat, rb)try: try: for line in file_object: while True: # process line chunk = file_object.read(256) # maybe: if not chunk: # print line.rstrip() break pass # process chunk...finally: finally: file_object.close() file_object.close()
  • Apriamo in lettura... F.readlines() -> una lista di stringhe F.xreadlines() -> iteratore di stringhe F.readline() -> una linea F.seek(p), F.tell(P), F.flush()... chunk_size = 256file_object = open(thefile.txt) file_object = open(binary_file.dat, rb)try: try: for line in file_object: while True: # process line chunk = file_object.read(256) # maybe: if not chunk: # print line.rstrip() break pass # process chunk...finally: finally: file_object.close() file_object.close()
  • Un po’ di generatori...
  • Un po’ di generatori... Leggere un chunk alla volta esplicitamente ripete la logica di iterare su un chunk
  • Un po’ di generatori... Leggere un chunk alla volta esplicitamente ripete la logica di iterare su un chunk def chunk_iterator(filename, chunksize=100): file_object = open(filename) try: while True: chunk = file_object.read(chunksize) if not chunk: break yield chunk finally: file_object.close() for chunk in chunk_iterator(binary_file.dat): do_smt_with_chunk(chunk)
  • Un po’ di generatori... Leggere un chunk alla volta esplicitamente ripete la logica di iterare su un chunk def chunk_iterator(filename, chunksize=100): file_object = open(filename) try: while True: chunk = file_object.read(chunksize) if not chunk: break yield chunk finally: file_object.close() for chunk in chunk_iterator(binary_file.dat): do_smt_with_chunk(chunk) Se astraiamo, possiamo scrivere in modo che funzioni con qualunque oggetto file-like
  • Scrivere Scrivere é facile: Metodo F.write(str) Metodo F.writelines(str) print >> handle, <0+ expr> print >> fh, “%d: %s “ % (lineno, line.upper()) Non ci soffermeremo molto
  • File-like objects Fino a questo modo abbiamo parlato di “oggetti file”. Di fatto avremmo fatto meglio a parlare di oggetti “file-like” Possiamo scrivere codice pensato un file e dargli in pasto un qualunque oggetto che si comporti come un file Es. StringIO, definito in cStringIO (o StringIO)
  • import sysfrom cStringIO import StringIOdef enumerate_lines(fin, fout): for lineno, line in enumerate(fin): fout.write(%8d: %s % (lineno, line))
  • import sysfrom cStringIO import StringIOdef enumerate_lines(fin, fout): for lineno, line in enumerate(fin): fout.write(%8d: %s % (lineno, line))file_object = open(__file__) # __file__ path del modulotry: enumerate_lines(file_object, sys.stdout)finally: file_object.close()
  • import sysfrom cStringIO import StringIOdef enumerate_lines(fin, fout): for lineno, line in enumerate(fin): fout.write(%8d: %s % (lineno, line))file_object = open(__file__) # __file__ path del modulotry: enumerate_lines(file_object, sys.stdout)finally: file_object.close()file_object = open(__file__)buffer_out = StringIO()try: enumerate_lines(file_object, buffer_out) buffer_out.seek(0) print buffer_out.read()finally: buffer_out.close() file_object.close()
  • import sysfrom cStringIO import StringIOdef enumerate_lines(fin, fout): for lineno, line in enumerate(fin): fout.write(%8d: %s % (lineno, line)) buffer_in = StringIO(import sys for line in sys.stdin: print line.rstrip() ) enumerate_lines(buffer_in, sys.stdout)
  • Niente magia... StringIO non è magico Rispetta l’interfaccia di un file Programmare per un’interfaccia e non per un’implementazione è un cardine della programmazione OO, e Python la porta al massimo livello StringIO si può comportare come un file in lettura o in scrittura StringIO.StringIO → lento cStringIO.StringIO → veloce
  • ... solo Duck Typingimport timeclass DateWriter(object): def __init__(self, handle_or_name, mode=w): try: handle_or_name.write self.fh = handle_or_name except AttributeError: self.fname = handle_or_name # check mode is write mode... self.fh = open(self.fname, mode) def write(self, string): return len(self.fh.write([%24s] %s % (time.ctime(), string)))
  • Pensiamo a Java/C++...Nei linguaggi con un type-system derivatoda C++ chiediamo che i parametri di unacerta funzione abbiano un dato tipo (osiano di un sottotipo)Questo è poco flessibile: programmare perun interfaccia Interfacce di Java (vero polimorfismo din.) Templates di C++ (polimorfismo statico) Sono soluzioni con problemi
  • Libri, ricerca per titolo class Book(object): def __init__(self, title, author): self.title = title self.author = author def find_by_title(seq, title): for item in seq: if type(item) == Book: # horrible if item.title == title: return item else: raise TypeError def find_by_author(seq, author): for item in seq: if type(item) == Book: # horrible if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloChiamare su una lista class Book(object): def __init__(self, title, author):che contiene un “non self.title = title self.author = authorlibro” lancia eccezione def find_by_title(seq, title): for item in seq: if type(item) == Book: # horrible if item.title == title: return item else: raise TypeError def find_by_author(seq, author): for item in seq: if type(item) == Book: # horrible if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloChiamare su una lista class Book(object): def __init__(self, title, author):che contiene un “non self.title = title self.author = authorlibro” lancia eccezione def find_by_title(seq, title):Eppure non gestiamo for item in seq: if type(item) == Book: # horriblenemmeno sottoclassi if item.title == title: return item else: raise TypeError def find_by_author(seq, author): for item in seq: if type(item) == Book: # horrible if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloChiamare su una lista class Book(object): def __init__(self, title, author):che contiene un “non self.title = title self.author = authorlibro” lancia eccezione def find_by_title(seq, title):Eppure non gestiamo for item in seq: if type(item) == Book: # horriblenemmeno sottoclassi if item.title == title: return item else:Peggior codice raise TypeErrorpossibile, inoltre def find_by_author(seq, author):stiamo risolvendo un for item in seq: if type(item) == Book: # horriblenon-problema if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloChiamare su una listache contiene un “nonlibro” lancia eccezioneEppure non gestiamonemmeno sottoclassiPeggior codicepossibile, inoltrestiamo risolvendo unnon-problema
  • Libri, ricerca per titolo class Book(object): def __init__(self, title, author): self.title = title self.author = author def find_by_title(seq, title): for item in seq: if isinstance(item, Book): # bad if item.title == title: return item else: raise TypeError def find_by_author(seq, author): for item in seq: if isinstance(item, Book): # bad if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloOra gestiamo class Book(object): def __init__(self, title, author):sottoclassi self.title = title self.author = author def find_by_title(seq, title): for item in seq: if isinstance(item, Book): # bad if item.title == title: return item else: raise TypeError def find_by_author(seq, author): for item in seq: if isinstance(item, Book): # bad if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloOra gestiamo class Book(object): def __init__(self, title, author):sottoclassi self.title = title self.author = authorEppure noi non usiamo def find_by_title(seq, title):mai il fatto che la cosa for item in seq: if isinstance(item, Book): # badsia un libro if item.title == title: return item else: raise TypeError def find_by_author(seq, author): for item in seq: if isinstance(item, Book): # bad if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloOra gestiamo class Book(object): def __init__(self, title, author):sottoclassi self.title = title self.author = authorEppure noi non usiamo def find_by_title(seq, title):mai il fatto che la cosa for item in seq: if isinstance(item, Book): # badsia un libro if item.title == title: return item else: Solo che ha un titolo raise TypeError def find_by_author(seq, author): for item in seq: if isinstance(item, Book): # bad if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloOra gestiamo class Book(object): def __init__(self, title, author):sottoclassi self.title = title self.author = authorEppure noi non usiamo def find_by_title(seq, title):mai il fatto che la cosa for item in seq: if isinstance(item, Book): # badsia un libro if item.title == title: return item else: Solo che ha un titolo raise TypeError Solo che ha un autore def find_by_author(seq, author): for item in seq: if isinstance(item, Book): # bad if item.author == author: return item else: raise TypeError
  • Libri, ricerca per titoloOra gestiamo class Song(object): def __init__(self, title, author):sottoclassi self.title = title self.author = authorEppure noi non usiamo def find_by_title(seq, title):mai il fatto che la cosa for item in seq: if isinstance(item, Book): # badsia un libro if item.title == title: return item else: Solo che ha un titolo raise TypeError Solo che ha un autore def find_by_author(seq, author): for item in seq:Cosa succede se if isinstance(item, Book): # bad if item.author == author:abbiamo una classe else: return itemSong? raise TypeError
  • Libri, ricerca per titoloOra gestiamo class Song(object): def __init__(self, title, author):sottoclassi self.title = title self.author = authorEppure noi non usiamomai il fatto che la cosasia un libro Solo che ha un titolo Solo che ha un autoreCosa succede seabbiamo una classeSong?
  • Libri e canzoni La cosa più semplice è la miglioreclass Book(object): def __init__(self, t, a): self.title = t I programmatori tendono a self.author = a non scrivere codice a casodef find_by_title(seq, title): for item in seq: Abbiamo sempre eccezioni if item.title == title: return item lanciatedef find_by_author(seq, author): I test servono apposta per for item in seq: if item.author == author: prendere ‘sta roba return item
  • E se avessimo film?I film hanno sempre un titolo, ma non hannoun autore, bensì un registafind_by_title dovrebbe funzionare, find_by_author,noInterfaccia per Book e Song. E per Movie?Design Pattern o duplicazione di codiceRuota quadrata strade per ruote quadrateCon il duck typing non dobbiamo cambiarenulla
  • Fail early Il problema con il nostro approccio si ha solo nella scrittura di codice exception safe Il codice può non trovare metodi dopo la modifica di qualche oggetto non locale def add(stack): Add top two elements on stack and put the result on the top >>> s = Stack([1, 2]) >>> add(s) >>> s.top() 3 >>> add(s) Traceback (most recent call last): ... IndexError: pop from empty list op1 = stack.pop(); op2 = stack.pop() stack.push(op1 + op2)
  • Fail early Il problema con il nostro approccio si ha solo nella scrittura di codice exception safe Il codice può non trovare metodi dopo la modifica di qualche oggetto non locale l = [1, 2] try: add(l) except: print l # => l = []
  • Fail early Il problema con il nostro approccio si ha solo nella scrittura di codice exception safe Il codice può non trovare metodi dopo la modifica di qualche oggetto non locale def add(stack): ... pop = stack.pop push = stack.push op1 = pop() op2 = pop() push(op1, op2)
  • Fail early Il problema con il nostro approccio si ha solo nella scrittura di codice exception safe Il codice può non trovare metodi dopo la modifica di qualche oggetto non locale
  • Passaggio di parametri
  • Passaggio di parametriNell call-site i parametriformali vengono legati agliargomenti attuali dellachiamata
  • Passaggio di parametriNell call-site i parametriformali vengono legati agliargomenti attuali dellachiamataI parametri sono quindivariabili locali nel corpodella funzione
  • Passaggio di parametriNell call-site i parametri Il passaggio è per valore,formali vengono legati agli ma è il valoreargomenti attuali della dell’etichetta, quello cuichiamata puntaI parametri sono quindivariabili locali nel corpodella funzione
  • Passaggio di parametriNell call-site i parametri Il passaggio è per valore,formali vengono legati agli ma è il valoreargomenti attuali della dell’etichetta, quello cuichiamata puntaI parametri sono quindi In particolare possiamovariabili locali nel corpo riassegnare, questo, comedella funzione previsto, non modifica il codice esterno
  • Passaggio di parametriNell call-site i parametri Il passaggio è per valore,formali vengono legati agli ma è il valoreargomenti attuali della dell’etichetta, quello cuichiamata puntaI parametri sono quindi In particolare possiamo def foo(a, b):variabili locali nel corpo riassegnare, 0: if a % 2 == questo, comedella funzione previsto,2non+modifica il a= *a 1 return a + b codice esterno x=4 y=4 print foo(x, y) print x, y
  • Quindi...def add(L, item): if item not in L: L.append(item)def add2(L, item): if item not in L: L.append(item) L = []def add3(L, item): L = [] L.append(item)
  • Quindi... x = []def add(L, item): add(x, 4) if item not in L: print x L.append(item)def add2(L, item): if item not in L: L.append(item) L = []def add3(L, item): L = [] L.append(item)
  • Quindi... x = []def add(L, item): add(x, 4) [4] if item not in L: print x L.append(item)def add2(L, item): if item not in L: L.append(item) L = []def add3(L, item): L = [] L.append(item)
  • Quindi...def add(L, item): if item not in L: L.append(item)def add2(L, item): if item not in L: x = [] L.append(item) add2(x, 4) L = [] print xdef add3(L, item): L = [] L.append(item)
  • Quindi...def add(L, item): if item not in L: L.append(item)def add2(L, item): if item not in L: x = [] L.append(item) add2(x, 4) [4] L = [] print xdef add3(L, item): L = [] L.append(item)
  • Quindi...def add(L, item): if item not in L: L.append(item)def add2(L, item): if item not in L: L.append(item) L = []def add3(L, item): L = [] x = [] L.append(item) add3(x, 4) print x
  • Quindi...def add(L, item): if item not in L: L.append(item)def add2(L, item): if item not in L: L.append(item) L = []def add3(L, item): L = [] x = [] L.append(item) add3(x, 4) [] print x
  • Quindi...def add(L, item): if item not in L: L.append(item)def add2(L, item): if item not in L: L.append(item) L = []def add3(L, item): L = [] L.append(item)
  • Optional parameters/Named parametersAttenzione a non confondere namedparameters e parametri opzionali, lasintassi è simile ma: I parametri opzionali sono parametri formali specificati nella dichiarazione delle funzione I named parameters sono parametri attuali presenti nel call-site della funzione Quasi ogni funzione può essere chiamata con named parameters, anche se non sempre é naturale farlo
  • Parametri Opzionali (1) def sum(seq, acc=0): Sums elements of seq acc is the starting value of the sum. for item in seq: acc += item return acc Un parametro opzionale è Quando una chiamata non specificato come id=exp fornisce un parametro Il def valuta exp e salva un opzionale, viene usato tale riferimento al valore fra gli valore attributi dell’oggetto Attenzione con oggetti funzione mutabili!
  • Parametri Opzionali (2) SBAGLIATO def concat_all(seq, acc=[]): for iterable in seq: acc.extend(iterable) return acc print concat_all([[1, 2], [3], [4, 5]]) # => [1, 2, 3, 4, 5] print concat_all([[a, b], [c]]) # => [1, 2, 3, 4, 5, a, b, c]
  • Parametri Opzionali (2) GIUSTO def concat_all(seq, acc=None): acc = acc or [] for iterable in seq: acc.extend(iterable) return acc print concat_all([[1, 2], [3], [4, 5]]) # => [1, 2, 3, 4, 5] print concat_all([[a, b], [c]]) # => [1, 2, 3, 4, 5, a, b, c]
  • SortLe liste hanno un metodo L.sort() in-placeL.sort(cmp=None, key=None, reverse=False) key: funzione applicata ad ogni elemento che ne da il valore per l’ordinamento reverse: vogliamo l’ordine inverso?sorted è un built-in che fa la stessa cosaapplicato ad un iterabile restituisce unalista
  • SortLe liste hanno un metodo L.sort() in-placeL.sort(cmp=None, key=None, reverse=False) key: funzione applicata ad ogni elemento che ne da il valore per l’ordinamento reverse: vogliamo l’ordine inverso?sorted è un built-in che fa la stessa cosaapplicato ad un iterabile restituisce unalista >>> d = dict(a=1, b=2, c=0) >>> sorted(d, key=d.get) # <= [c, a, b]
  • ModuliUn modulo è un oggetto al quale sipossono legare (e del quale si possonoreferenziare) gli attributiNormalmente il codice di un modulo anamesta nel file aname.py Spesso si “confonde” il concetto di modulo con quello di sorgente python (di fatto ci sono modi esotici per creare al volo moduli)Un modulo è anche uno spazio dei nomiisolato
  • ImportSe foo.py è un file Python nel path disistema (equivalente del classpath) conimport foo [as another_name][, ...]importiamo il file come moduloGli statements nel corpo del modulovengono eseguiti (def/class sonstatements)Si crea un nuovo spazio dei nomi e gliattributi del modulo (comprese funzioni eclassi) sono accessibili come foo.name
  • Esempiosimple_module.py >>> import simple_moduleclass Spam(object): >>> simple_module.Spam() pass <simple_module.Spam ...> >>> e = simple_module.Eggs()class Eggs(object): >>> simple_module.menu(e) pass [<simple_module.Eggs ...>, <simple_module.Spam ...>]def menu(course): >>> simple_module.base_menu return [course,Spam()] [<simple_module.Eggs ...>, <simple_module.Spam ...>]base_menu = menu(Eggs())
  • Import esegue sempretutto?Il fatto che import esegua sempre tutto ilcodice può essere seccante in moltecircostanzeFacciamo un esempio quasi reale.Scriviamo un semplice programma che usaSQLite per mantenere una collezione dilibriSemplice vuole dire una tabella e nongestiamo come si deve chiave, inserimentimultipli etc (quella è roba di SQL
  • import os, sysimport sqlite3class Book(object): Represents a Book in our model def __init__(self, title, author): self.title = title self.author = author def __str__(self): return %s, %s % (self.title, self.author)class Library(object): Represents the library in our model. def __init__(self, db_name): self.open_db(db_name) def open_db(self, fname): Open specified db. Create it if it does not exist if not os.path.exists(fname): self._initialize_db(fname) self.conn = sqlite3.connect(fname) def _initialize_db(self, fname): conn = sqlite3.connect(fname) c = conn.cursor() c.execute(create table books(title string, author string)) conn.commit() c.close()
  • ... # continua da Library def print_books(self, out=sys.stdout): Print all the book to supplied output. Default: sys.stdout c = self.conn.cursor() c.execute(select title, author from books) for author, title in c: print >> out, author, title def books(self): Return a list of all books in memory c = self.conn.cursor() c.execute(select title, author from books) return [Book(author, title) for author, title in c] def find(self, author=None, title=None): Find book by author or title c = self.conn.cursor() if author: c.execute(select title, author from books where author like ?, (author, )) elif title: c.execute(select title, author from books where title like ?, (title, )) else: raise Exception return [Book(author, title) for author, title in c]
  • lib = Library(books.db)lib.insert(Book(Alex Martelli, Python in a Nutshell))lib.insert(Book(Marco Beri, Python))lib.insert(Book(Marco Beri, Sviluppare applicazioni web con Django)) Abbiamo definito due classi Il codice in questa slide è direttamente nel corpo del modulo Viene eseguito ad ogni import Noi vogliamo che sia eseguito solo quando il tutto è chiamato da command line
  • Abbiamo definito due classi Il codice in questa slide è direttamente nel corpo del modulo Viene eseguito ad ogni import Noi vogliamo che sia eseguito solo quando il tutto è chiamato da command lineif __name__ == __main__: lib = Library(books.db) lib.insert(Book(Alex Martelli, Python in a Nutshell)) lib.insert(Book(Marco Beri, Python)) lib.insert(Book(Marco Beri, Sviluppare applicazioni web con Django))
  • Abbiamo definito due classi Il codice in questa slide è direttamente nel corpo del modulo Viene eseguito ad ogni import Noi vogliamo che sia eseguito solo quando il tutto è chiamato da command lineif __name__ == __main__: lib = Library(books.db) lib.insert(Book(Alex Martelli, Python in a Nutshell)) lib.insert(Book(Marco Beri, Python)) lib.insert(Book(Marco Beri, Sviluppare applicazioni web con Django)) __name__ normalmente vale il nome del modulo, vale ‘__main__’ quando il modulo è chiamato come progr.
  • NOTA A MARGINE Abbiamo definito due classi In un progetto Python vero, probabilmente Il codice in questa slide è direttamente nel ORM si vorrebbe usare SQLAlchemy, come corpo del modulo o semplicemente come astrazione dal DB. Viene eseguito ad ogni import Noi vogliamoèche siausato e comodo, sebbene Di fatto molto eseguito solo quando fuori dallo scopecommand presentazione il tutto è chiamato da di questa line Con Django invece probabilmente si userebbeif __name__ == __main__: lib = Library(books.db) il suo ORM. Il modulo SQLite è comunque lib.insert(Book(Alex Martelli, Python in a Nutshell)) lib.insert(Book(Marco Beri, Python)) comodo da avere pronto. lib.insert(Book(Marco Beri, Sviluppare applicazioni web con Django)) __name__ normalmente vale il nome del modulo, vale ‘__main__’ quando il modulo è chiamato come progr.
  • ReloadSe si è nell’interprete interattivo, è possibilericaricare un modulo con l’espressionereload(nomemodulo) Il modulo doveva essere stato importato con lo statement importreload non è una soluzione pronta per fare hot-swap di codice, risolve il problema di facilitarelo sviluppo con l’interprete interattivoL’hot-swap non è un argomento di frontiera inPython, sul Cookbook ci sono diverse ricette
  • PackagesPython offre anche packages, ovvero“moduli che contengono altri moduli” Es. os.path.join(...): path é un sottomodulo Non mostriamo qui come farli, a livello base si ha una dir con un __init__.py e altri moduli dentroAnche un file .zip può comportarsi comeun package
  • Testing 39Nella programmazione odierna il testing èessenzialeNessun gruppo pensa di poter sviluppareun software minimamente complessosenza usare abbondantemente i testOrmai sono standard metodologie comeTDD (test driven developement) anche al difuori di ambienti agiliPython è TDD ready
  • Doctest (1) Il modo più semplice di scrivere test in Python è utilizzando le stesse docstrings def concat_all(seq, acc=None): Concatenate a list of strings. >>> concat_all([[1, 2], [3], [4, 5]]) [1, 2, 3, 4, 5] >>> concat_all([[a, b], [c]]) [a, b, c] acc = acc or [] for iterable in seq: acc.extend(iterable) return acc
  • Doctest (2)Concatenate a list of strings.>>> concat_all([[1, 2], [3], [4, 5]])[1, 2, 3, 4, 5]>>> concat_all([[a, b], [c]])[a, b, c] Nella documentazione ci sono esempi, “come presi dall’inteprete python interattivo” Potremmo verificare che l’output presentato nell’esempio è quello
  • Doctest (3) Per fare questo, basta mettere in fondo al modulo: if __name__ == __main__: import doctest doctest.testmod() Doctest è comodo, arricchisce la documentazione di esempi (eseguibili), ma non si presta ad unit-testing su larga scala Guarda il modulo standard unittest... ... o ancora meglio nosetest
  • Lint Scrivere assolutamente i test... ... ma anche un analizzatore statico può essere comodo Pyflakes Pylint Catturano alcuni errori staticamente (leggere variabili non assegnate, usare attributi non presenti) Danno metriche sulla qualità del codice
  • Libreria standard Imparare a guardare nella libreria standard con pydoc. Pochi (~2%) esempi: zlib: crc, (de)compressione di buffer collections (deque) ctypes: facile interfacciamento dinamico con codice C cmd: creazione di UI testuali interattive copy: protocolli di copia bisect (ricerca binaria), heapq (priority
  • Socket UDP: server import os import socket def server(port=8081): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(("", port)) print "Waiting on port", port try: while True: data, addr = s.recvfrom(1024) print "Received:", data, "from", addr except KeyboardInterrupt: print "Quitting..." finally: s.close()
  • Socket UDP: client def client(port=8081, host=localhost): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(Hello, [remote] world!, (host, port)) def improved_client(msg, port=8081, host=localhost, bufsize=1024): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while msg: bytes_sent = s.sendto(msg[:bufsize], (host, port)) msg = msg[bytes_sent:]
  • Socket UDP: client def client(port=8081, host=localhost): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(Hello, [remote] world!, (host, port)) def improved_client(msg, port=8081, host=localhost, bufsize=1024): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while msg: bytes_sent = s.sendto(msg[:bufsize], (host, port)) msg = msg[bytes_sent:] if __name__ == __main__: pid = os.fork() if pid: server() else: client() client() improved_client(WOW! IT WORKS)
  • SNTP Client import socket, struct, sys, time TIME1970 = 2208988800L client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) data = x1b + 47 * 0 client.sendto(data, (sys.argv[1], 123)) data, address = client.recvfrom(1024) if data: print Response received from:, address t = struct.unpack(!12I, data)[10] t -= TIME1970 print tTime=%s % time.ctime(t)
  • SNTP Client import socket, struct, sys, time TIME1970 = 2208988800L client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) % python sntp_client.py time.euro.apple.com data = x1b + 47 * 0 client.sendto(data, (sys.argv[1], (17.72.255.12, 123) Response received from: 123)) Time=Sat Apr 4 19:46:09 2009 data, address = client.recvfrom(1024) if data: print Response received from:, address t = struct.unpack(!12I, data)[10] t -= TIME1970 print tTime=%s % time.ctime(t)
  • Serializzazione Serializzare un oggetto in modo portabile è in generale un problema non banale In C++ è particolarmente seccante per questioni di endianness e dimensione dei tipi In Python è fornito dalla libreria standard: Pickle (cPickle): general purpose Marshal: funziona con tipi builtin e oggetti codice (usato anche per i compilati python)
  • cPicklecPickle è l’implementazione in CDue metodi principali, load e dumpFunziona con qualunque oggetto file-like: dump chiede write(s) load chiede read(d) e readline()Gestisce cicli, referenze multiple, etc...Possiamo usare socket al posto di file? sock.makefile([mode[, bufsize]])
  • # -*- coding: utf-8 -*-from __future__ import with_statementimport cPickle as pickleclass Person(object): def __init__(self, name, surname): self.name = name self.surname = surname def marries(self, person): self.spouse = person person.spouse = self def __str__(self): base = %s %s % (self.name, self.surname) if hasattr(self, spouse): base += -> %s %s % (self.spouse.name, self.spouse.surname) return baseluthien = Person(Lúthien, Tinúviel)beren = Person(Beren, Erchamion)beren.marries(luthien)print berenprint luthien
  • with open(couple.dat, wb) as f: pickle.dump(beren, f, pickle.HIGHEST_PROTOCOL)# pickle.dump(luthien, f, pickle.HIGHEST_PROTOCOL)del berendel luthienwith open(couple.dat, rb) as f: beren = pickle.load(f)# luthien = pickle.load(f)luthien = beren.spouseprint berenprint luthien
  • import os, sys, socketclass Server(object): def __init__(self, host, port): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind((host, port)) self.sock.listen(5) def __iter__(self): while True: connection, address = self.sock.accept() fh = connection.makefile(rb) while True: obj = pickle.load(fh) yield objclass Client(object): def __init__(self, host, port): self.host = host self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.host, self.port)) self.fh = self.sock.makefile(wb) def send(self, obj): pickle.dump(obj, self.fh)
  • if __name__ == __main__: pid = os.fork() if pid: for obj in Server(, 9876): print obj if obj == quit: sys.exit(0) else: luthien = Person(Lúthien, Tinúviel) beren = Person(Beren, Erchamion) beren.marries(luthien) cl = Client(, 9876) cl.send(beren) cl.send(luthien) cl.send(quit) Attenzione: Python offre classi come TPCServer, UDPServer, ThreadingTCPServer, ThreadingUDPServer, SimpleHTTPServer, CGIHTTPServer.
  • if __name__ == __main__: pid = os.fork() if pid: for obj in Server(, 9876): print obj if obj == quit: sys.exit(0) else: luthien = Person(Lúthien, Tinúviel) beren = Person(Beren, Erchamion) beren.marries(luthien) cl = Client(, 9876) cl.send(beren) cl.send(luthien) cl.send(quit) Attenzione: Python offre classi come TPCServer, UDPServer, ThreadingTCPServer, ThreadingUDPServer, SimpleHTTPServer, CGIHTTPServer.NON DIMENTICARE TWISTED
  • Python e POSIXPython offre numerose funzioni familiari achi viene dalla programmazione POSIX Molte sono in os, qualcuna in sys, socket, time (time.sleep), socket, mmaps, popen2 In generale conoscere la libreria standard aiuta (Python in a Nutshell o pydoc)Non sempre però è il modo migliore: Ci sono librerie di livello più alto
  • subprocessSubprocess è una libreria di alto livello chefunziona su Unix (e altro) e WinServe per creare figli e maneggiare il loroinput-output in maniera facile class Popen(args, bufsize=0, executable=None,             stdin=None, stdout=None, stderr=None,             preexec_fn=None, close_fds=False, shell=False,             cwd=None, env=None, universal_newlines=False,             startupinfo=None, creationflags=0):
  • PexpectSe l’input/output fra padre e figlio èparticolarmente interattivo: pexpectEs. il figlio è pensato per essere pilotato daun umano
  • Client di rete in Python urlparse: parsing di url (urljoin, urlsplit) urllib: leggere dati da http/https/ftp/file urllib2: sopra-insieme di urllib, un po’ più complesso e più ricco poplib: interrogare server POP3 imaplib: interrogare server IMAP4 smtplib: inviare mail con SMTP httplib/ftplib nntplib: leggere e inviare messaggi Usenet
  • emailIl package email è una delleimplementazioni più ricche e fedeli deglistandard relativiRende semplice costruire messaggi ditesto semplice come complessi messaggimultipartSpecifico e poco generale: ricordatevi cheesiste, se vi serve esempi su web + doc
  • Server side modulesScriviamo un gestore (“handler”) checontiene il codice per implementare ilprotocolloCreiamo un server cui passiamo l’handler Il server gestisce i dettagli, noi il protocollo Server prefabbricati: TCPServer ForkingUDPServer UDPServer ThreadingTCPServe r ForkingTCPServer
  • Parsing XMLLibreria standard SaX DOM (minidom, pulldom)BeautifulSoup Parserizza anche XML e HTML mal formatoElementTree Interfaccia molto pythonica
  • Interfacce grafiche Tkinter Multipiattaforma, libreria standard, bruttarello Qt Piattaforma ricchissima, cross-platform, ++ wx Cross-platform, ... [non inneschiamo flames] GTK, Cocoa, WinAPI, + .Net con
  • Webcgi (sconsigliato)/fastcgiWSGI: modulo di medio livello per interfacciarsi con iserverDjango: framework completo, molto usatoNevow: framework completo basato su TwistedZope2/3: “mega framework”Google App Engine (+web.py ev. Django)web.py: modulo minimalista, facile comprensione
  • Web.py import web urls = ( /(.*), hello ) app = web.application(urls, globals()) class hello: def GET(self, name): if not name: name = world return Hello, + name + ! if __name__ == "__main__": app.run()
  • ipythonOltre all’interprete interattivo standard, sipuò installare ipython, una shell python Help più esteso Funzioni di introspezione e completamento dinamico del codice ...