• Save
Pyimproved again
Upcoming SlideShare
Loading in...5
×
 

Pyimproved again

on

  • 494 views

Object Oriented programming in Python.

Object Oriented programming in Python.

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

Statistics

Views

Total Views
494
Views on SlideShare
490
Embed Views
4

Actions

Likes
1
Downloads
0
Comments
0

1 Embed 4

http://www.linkedin.com 4

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

Pyimproved again Pyimproved again Presentation Transcript

  • UlterioriapprofondimentiPythonEnrico Franchienrico.franchi@gmail.comfranchi@cs.unipr.it
  • Aumentare il dinamismoPython offre come builtin getattr, setattr ehasattr f.foo getattr(f, ‘foo’) f.foo = 4 setattr(f, ‘foo’, 4) hasattr controlla solo se c’è l’attributoQuesto vuole dire che possiamo chiedereun attributo a runtime conoscendone ilnomeForte capacità di introspezione (assieme al
  • Esempioclass Capsule(object): def __init__(self, obj): self.obj = obj def get(self, attribute_path): parts = attribute_path.split(.) current_obj = self.obj for attribute in parts: current_obj = getattr(current_obj, attribute) return current_objif __name__ == "__main__": d = datetime.date(1983, 7, 1) e = Capsule(Employee(Enrico Franchi, d)) print e.get(birth_date.month)
  • Ripasso MROSia a oggetto di tipo A, sottoclasse di B eCa.foo cerca nell’ordine:1.fra gli attributi dell’oggetto a2.fra gli attributi dell’oggetto classe A3.fra gli attributi dell’oggetto classe B4.fra gli attributi dell’oggetto classe CSe non viene trovato, viene lanciatoAttributeError
  • Eppure...Di fatto prima di lanciare AttributeError, sivede se è disponibile un metodo__getattr__(self, name)In questo caso viene passato il nomedell’attributo come stringa (in name)Il corpo di __getattr__ può specificare cosaritornare (o se lanciare eccezione)NB: siccome i metodi sono anche attributi,funziona anche con loroPer i “PRO” ci sono anche i descrittori...
  • Esempioclass Capsule(object): def __init__(self, obj): self.obj = obj def get(self, attribute_path): parts = attribute_path.split(.) current_obj = self.obj for attribute in parts: current_obj = getattr(current_obj, attribute) return current_obj def __getattr__(self, attribute): return getattr(self.obj, attribute)
  • Esempioclass Capsule(object): def __init__(self, obj): self.obj = obj def get(self, attribute_path): parts = attribute_path.split(.) current_obj = self.obj for attribute in parts: current_obj = getattr(current_obj, attribute) return current_obj def __getattr__(self, attribute): return getattr(self.obj, attribute) Facile delegare... (pensate un po’ al decorator pattern...)
  • Esempioclass Enum(object): def __init__(self, *args, **kargs): self._enums = dict(((name, i) for i, name in enumerate(args))) min_val, max_val = 0, len(args) for k, v in kargs.iteritems(): if min_val < v < max_val: raise ValueError, (Value %s already specified % v) else: self._enums[k] = v def __getattr__(self, name): try: return self._enums[name] except KeyError: raise AttributeError
  • Esempioclass Enum(object): def __init__(self, *args, **kargs): self._enums = dict(((name, i) for i, name in enumerate(args))) min_val, max_val = 0, len(args) for k, v in kargs.iteritems(): if min_val < v < max_val: raise ValueError, (Value %s already specified % v) else: self._enums[k] = v def __getattr__(self, name): try: return self._enums[name] except KeyError: raise AttributeError Per Enum fatte a modo, qui. Meglio ancora le named tuples.
  • Funzioni create a runtimeclass Collection(object): def __init__(self, l=None): self.buf = l or [] def find(self, **kargs): temp_buf = self.buf for k, v in kargs.iteritems(): temp_buf = [item for item in temp_buf if getattr(item, k) == v] return temp_buf
  • Funzioni create a runtimeclass Collection(object): def __init__(self, l=None): self.buf = l or [] def find(self, **kargs): temp_buf = self.buf for k, v b1 kargs.iteritems(): in = book.Book(Python in a Nutshell, Alex Martelli) temp_buf = [item for item in temp_buf Alex Martelli) b2 = book.Book(Python Cookbook, b3 if getattr(item, k) == v] = book.Book(Python, Marco Beri) return temp_buf b4 = book.Book(Sviluppare applicazioni web con Django, Marco Beri) b5 = book.Book(Espressioni Regolari, Marco Beri) c = Collection([b1, b2, b3, b4, b5]) for b in c.find(title=Python, author=Marco Beri): print b
  • Funzioni create a runtimeclass Collection(object): def __init__(self, l=None): self.buf = l or [] def find(self, **kargs): temp_buf = self.buf for k, v in kargs.iteritems(): temp_buf = [item for item in temp_buf if getattr(item, k) == v] return temp_buf @classmethod def add_method(cls, func, name): func.im_class = cls func.im_func = func func.im_self = None func.func_name = name setattr(cls, name, func)
  • __getattr__ avanzatodef __getattr__(self, name): if name.startswith(find_by_): key = name[8:] def _aux(self, value): return Collection.find(self, **{key : value}) Collection.add_method(_aux, name) return getattr(self, name) else: raise TypeError
  • __getattr__ avanzatodef __getattr__(self, name): if name.startswith(find_by_): key = name[8:] def _aux(self, value): return Collection.find(self, **{key : value}) Collection.add_method(_aux, name) return getattr(self, name) else: raise TypeError Creiamo una funzione a runtime
  • __getattr__ avanzatodef __getattr__(self, name): if name.startswith(find_by_): key = name[8:] def _aux(self, value): return Collection.find(self, **{key : value}) Collection.add_method(_aux, name) return getattr(self, name) else: raise TypeError Creiamo una funzione a runtime La facciamo diventare metodo della classe
  • __getattr__ avanzatodef __getattr__(self, name): if name.startswith(find_by_): key = name[8:] def _aux(self, value): return Collection.find(self, **{key : value}) Collection.add_method(_aux, name) return getattr(self, name) else: raise TypeError Creiamo una funzione a runtime La facciamo diventare metodo della classe Ora getattr la può trovare (nella fase 2.) e restituisce il metodo
  • __getattr__ avanzatodef __getattr__(self, name): if name.startswith(find_by_): key = name[8:] def _aux(self, value): return Collection.find(self, **{key : value}) Collection.add_method(_aux, name) return getattr(self, name) else: raise TypeError Creiamo una funzione a runtimefor b in c.find_by_author(Marco Beri): La facciamo diventare metodo della classe print bfor b in c.find_by_author(Alex Martelli): Ora getattr la può trovare (nella fase 2.) e print b restituisce il metodo
  • 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
  • HandlerPer ogni richiesta viene creato un nuovohandlerAlcuni server (Threading, Forking)gestiscono concorrenza, gli altri in serie con un server Forking di base le modifiche allo stato dei figli non si riflette sul padre con un Threading bisogna gestire lock, etc...
  • Handler (2) Si sottoclassa un handler (SocketServer.BaseRequestHandler) Si “overridda” handle(self) [e altro se opport.] Si hanno come variabili d’istanza self.request: la richiesta (socket) self.client_address: guess... self.server: un’istanza del server Entro certi limiti, si è indipendenti dal
  • Handler (2) Si sottoclassa un handler (SocketServer.BaseRequestHandler) Si “overridda” handle(self) [e altro se opport.] Chi scrive trova Si hanno come variabili d’istanza particolarmente self.request: la richiesta (socket) orrendo self.client_address: guess... il termine self.server: un’istanza del server Entro certi limiti, si è indipendenti dal
  • import SocketServerclass EchoHandler(SocketServer.BaseRequestHandler): def handle(self): print Connected from, self.client_address try: for message in self.messages(): if message.upper().startswith(QUIT): break self.request.sendall(message) finally: self.request.close() print Disconnected from, self.client_address def messages(self): while True: rec_data = self.request.recv(8192) if not rec_data: break yield rec_datatry: srv = SocketServer.ForkingTCPServer((, 8881), EchoHandler) srv.serve_forever()except KeyboardInterrupt: print Stopping server...
  • Scriviamo Gumball!Scriviamo un simulatore di macchine chedistribuiscono palline di gomma Inserisci un quarto di dollaro Gira la manovella Fatti restituire il quarto di dollaro [consegna la pallina]L’esempio viene da Head First DesignPatterns, Freeman&Freeman, O’Reilly
  • Il metodo tradizionaleclass GumballMachine(object): SOLD_OUT = 0 NO_QUARTER = 1 HAS_QUARTER = 2 SOLD = 3 def __init__(self, count): self.count = count self.state = GumballMachine.SOLD_OUT if self.count > 0: self.state = GumballMachine.NO_QUARTER def insert_quarter(self): if self.state == GumballMachine.HAS_QUARTER: print "You cant insert another quarter" elif self.state == GumballMachine.NO_QUARTER: self.state = GumballMachine.HAS_QUARTER print "You inserted a quarter" elif self.state == GumballMachine.SOLD_OUT: print "You cant insert a quarter, the machine is sold out" elif self.state == GumballMachine.SOLD: print "Please wait, we are already giving you a gumball"
  • Il metodo tradizionaledef eject_quarter(self): if self.state == GumballMachine.HAS_QUARTER: print "Quarter returned" self.state = GumballMachine.NO_QUARTER elif self.state == GumballMachine.NO_QUARTER: print "You havent inserted a quarter" elif self.state == GumballMachine.SOLD_OUT: print "You cant eject, you havent inserted a quarter yet" elif self.state == GumballMachine.SOLD: print "Sorry, you already turned the crank"def turn_crank(self): if self.state == GumballMachine.SOLD: print "Turning twice doesnt get you another gumball" elif self.state == GumballMachine.NO_QUARTER: print "You turned, but there is no quarter" elif self.state == GumballMachine.SOLD_OUT: print "You turned, but there is no quarter" elif self.state == GumballMachine.HAS_QUARTER: print "You turned..." self.state = GumballMachine.SOLD self.dispense()
  • Il metodo tradizionaledef dispense(self): if self.state == GumballMachine.SOLD: print "A gumball comes rolling out of the slot" self.count -= 1 if self.count == 0: print "Oops, out of gumballs" self.state = GumballMachine.SOLD_OUT else: self.state = GumballMachine.NO_QUARTER elif self.state == GumballMachine.NO_QUARTER: print "You need to pay first" elif self.state == GumballMachine.SOLD_OUT: print "No gumball dispensed" elif self.state == GumballMachine.HAS_QUARTER: print "No gumball dispensed"
  • Il metodo tradizionaledef dispense(self): if self.state == GumballMachine.SOLD: print "A gumball comes rolling out of the slot" self.count -= 1 if self.count == 0: print "Oops, out of gumballs" self.state = GumballMachine.SOLD_OUT else: self.state = GumballMachine.NO_QUARTER elif self.state == GumballMachine.NO_QUARTER: print "You need to pay first" elif self.state == GumballMachine.SOLD_OUT: print "No gumball dispensed" elif self.state == GumballMachine.HAS_QUARTER: print "No gumball dispensed" Ora supponiamo di volere aggiungere uno stato...
  • ENCAPSULATE WHAT VARIES
  • State pattern e protocolli Design pattern nei linguaggi dinamici State pattern Vediamo il punto di vista per implementare un protocollo?
  • Pattern state Gli stati sono rappresentati da oggetti L’oggetto principale “delega” le azioni ai metodi degli stati Eventualmente questi cambiano lo stato Aggiungere stati diventa facile
  • class GumballMachine(object): The true and only gumball machine actions = set([insert_quarter, eject_quarter, turn_crank, dispense]) def __init__(self, count): self.no_quarter = NoQuarterState(self) self.has_quarter = HasQuarterState(self) self.sold = SoldState(self) self.sold_out = SoldOutState(self) self.count = count self.state = self.sold_out if self.count > 0: self.state = self.no_quarter def __getattr__(self, action): if action in GumballMachine.actions: return getattr(self.state, action) def __str__(self): return ("nMighty Gumball, Incn" "Python-enabled Standing Gumball Model #2009n" "Built from orginal specifications by Freeman&Freeman," " Head First Design Patternsn" "Inventory: %d gumballsn") % (self.count)
  • class HasQuarterState(object): Represent a state where the machine has a quarter inside. def __init__(self, gumball): self.gumball = gumball def insert_quarter(self): Perform quarter insertion print "You cant insert another quarter" def eject_quarter(self): Ask the quarter back print "Quarter returned" self.gumball.state = self.gumball.no_quarter def turn_crank(self): Turn the crank print "You turned..." self.gumball.state = self.gumball.sold self.gumball.dispense() def dispense(self): Actually gives the gumball print "No gumball dispensed"
  • class NoQuarterState(object): Represent a state where the machine has no quarter inside. def __init__(self, gumball): self.gumball = gumball def insert_quarter(self): Perform quarter insertion self.gumball.state = self.gumball.has_quarter print "You inserted a quarter" def eject_quarter(self): Ask the quarter back print "You havent inserted a quarter" def turn_crank(self): Turn the crank print "You turned, but there is no quarter" def dispense(self): Actually gives the gumball print "You need to pay first"
  • class SoldState(object): The machine is to dispense the ball def __init__(self, gumball): self.gumball = gumball def insert_quarter(self): Perform quarter insertion print "Please wait, we are already giving you a gumball" def eject_quarter(self): Ask the quarter back print "Sorry, you already turned the crank" def turn_crank(self): Turn the crank print "Turning twice doesnt get you another gumball" def dispense(self): Actually gives the gumball print "A gumball comes rolling out of the slot" self.gumball.count -= 1 if self.gumball.count == 0: print "Oops, out of gumballs" self.gumball.state = self.gumball.sold_out else: self.gumball.state = self.gumball.no_quarter
  • class SoldOutState(object): No more balls. Sorry guys. def __init__(self, gumball): self.gumball = gumball def insert_quarter(self): Perform quarter insertion print "You cant insert a quarter, the machine is sold out" def eject_quarter(self): Ask the quarter back print "You cant eject, you havent inserted a quarter yet" def turn_crank(self): Turn the crank print "You turned, but there is no quarter" def dispense(self): Actually gives the gumball print "No gumball dispensed"
  • Setattr def __setattr__(self, name, value): ... __getattr__viene chiamato solo quando non si trova l’attributo, __setattr__ è chiamato sempre Attenzione ai loop se lo ridefinite! def __setattr__(self, name, value): if name in self.names: self.k = value * self.conversion[name] elif name == ‘k’: object.__setattr__(self, name, value) else: raise AttributeError, name
  • Q&A
  • 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()
  • XML-RPC Serverfrom SimpleXMLRPCServer import SimpleXMLRPCServerfrom SimpleXMLRPCServer import SimpleXMLRPCRequestHandlerclass RequestHandler(SimpleXMLRPCRequestHandler): rpc_paths = (/RPC2,)server = SimpleXMLRPCServer(("localhost", 8000), requestHandler=RequestHandler)server.register_introspection_functions()server.register_function(pow)def adder_function(x,y): return x + yserver.register_function(adder_function, add)class MyFuncs: def div(self, x, y): return x // yserver.register_instance(MyFuncs())server.serve_forever()
  • XML-RPC Client import xmlrpclib s = xmlrpclib.ServerProxy(http://localhost:8000) print s.pow(2,3) # Returns 2**3 = 8 print s.add(2,3) # Returns 5 print s.div(5,2) # Returns 5//2 = 2 # Print list of available methods print s.system.listMethods()