Ulteriori
approfondimenti
Python
Enrico Franchi
enrico.franchi@gmail.com
franchi@cs.unipr.it
Aumentare il dinamismo
Python offre come builtin getattr, setattr e
hasattr
  f.foo     getattr(f, ‘foo’)

  f.foo = 4     setattr(f, ‘foo’, 4)

  hasattr   controlla solo se c’è l’attributo
Questo vuole dire che possiamo chiedere
un attributo a runtime conoscendone il
nome
Forte capacità di introspezione (assieme al
Esempio
class 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




if __name__ == "__main__":
    d = datetime.date(1983, 7, 1)

  e = Capsule(Employee('Enrico Franchi', d))

  print e.get('birth_date.month')
Ripasso MRO
Sia a oggetto di tipo A, sottoclasse di B e
C
a.foo cerca nell’ordine:
1.fra gli attributi dell’oggetto a
2.fra gli attributi dell’oggetto classe A
3.fra gli attributi dell’oggetto classe B
4.fra gli attributi dell’oggetto classe C
Se non viene trovato, viene lanciato
AttributeError
Eppure...
Di fatto prima di lanciare AttributeError, si
vede se è disponibile un metodo
__getattr__(self, name)

In questo caso viene passato il nome
dell’attributo come stringa (in name)
Il corpo di __getattr__ può specificare cosa
ritornare (o se lanciare eccezione)
NB: siccome i metodi sono anche attributi,
funziona anche con loro
Per i “PRO” ci sono anche i descrittori...
Esempio
class 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)
Esempio
class 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...)
Esempio
class 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
Esempio
class 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 runtime
class 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 runtime
class 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 runtime
class 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__ avanzato
def __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__ avanzato
def __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__ avanzato
def __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__ avanzato
def __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__ avanzato
def __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
for b in c.find_by_author('Marco Beri'):
  La facciamo diventare metodo della classe
   print b

for b in c.find_by_author('Alex Martelli'):
  Ora getattr la può trovare (nella fase 2.) e
   print b

  restituisce il metodo
Server side modules
Scriviamo un gestore (“handler”) che
contiene il codice per implementare il
protocollo
Creiamo un server cui passiamo l’handler
  Il server gestisce i dettagli, noi il protocollo
  Server prefabbricati:
    TCPServer                       ForkingUDPServer
    UDPServer                       ThreadingTCPServe
                                    r
    ForkingTCPServer
Handler
Per ogni richiesta viene creato un nuovo
handler
Alcuni 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 SocketServer

class 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_data

try:
   srv = SocketServer.ForkingTCPServer(('', 8881), EchoHandler)
   srv.serve_forever()
except KeyboardInterrupt:
   print 'Stopping server...'
Scriviamo Gumball!
Scriviamo un simulatore di macchine che
distribuiscono 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 Design
Patterns, Freeman&Freeman, O’Reilly
Il metodo tradizionale
class 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 can't 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 can't 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 tradizionale
def 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 haven't inserted a quarter"
  elif self.state == GumballMachine.SOLD_OUT:
      print "You can't eject, you haven't 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 doesn't 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 tradizionale
def 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 tradizionale
def 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 can't 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 haven't 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 doesn't 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 can't insert a quarter, the machine is sold out"

  def eject_quarter(self):
    'Ask the quarter back'
    print "You can't eject, you haven't 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
Web
cgi (sconsigliato)/fastcgi
WSGI: modulo di medio livello per interfacciarsi con i
server
Django: framework completo, molto usato
Nevow: framework completo basato su Twisted
Zope2/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 Server
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler

class 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 + y
server.register_function(adder_function, 'add')

class MyFuncs:
   def div(self, x, y):
      return x // y
server.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()

Pyimproved again

  • 1.
  • 2.
    Aumentare il dinamismo Pythonoffre come builtin getattr, setattr e hasattr f.foo getattr(f, ‘foo’) f.foo = 4 setattr(f, ‘foo’, 4) hasattr controlla solo se c’è l’attributo Questo vuole dire che possiamo chiedere un attributo a runtime conoscendone il nome Forte capacità di introspezione (assieme al
  • 3.
    Esempio class 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 if __name__ == "__main__": d = datetime.date(1983, 7, 1) e = Capsule(Employee('Enrico Franchi', d)) print e.get('birth_date.month')
  • 4.
    Ripasso MRO Sia aoggetto di tipo A, sottoclasse di B e C a.foo cerca nell’ordine: 1.fra gli attributi dell’oggetto a 2.fra gli attributi dell’oggetto classe A 3.fra gli attributi dell’oggetto classe B 4.fra gli attributi dell’oggetto classe C Se non viene trovato, viene lanciato AttributeError
  • 5.
    Eppure... Di fatto primadi lanciare AttributeError, si vede se è disponibile un metodo __getattr__(self, name) In questo caso viene passato il nome dell’attributo come stringa (in name) Il corpo di __getattr__ può specificare cosa ritornare (o se lanciare eccezione) NB: siccome i metodi sono anche attributi, funziona anche con loro Per i “PRO” ci sono anche i descrittori...
  • 6.
    Esempio class 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)
  • 7.
    Esempio class 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...)
  • 8.
    Esempio class 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
  • 9.
    Esempio class 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.
  • 10.
    Funzioni create aruntime class 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
  • 11.
    Funzioni create aruntime class 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
  • 12.
    Funzioni create aruntime class 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)
  • 13.
    __getattr__ avanzato def __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
  • 14.
    __getattr__ avanzato def __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
  • 15.
    __getattr__ avanzato def __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
  • 16.
    __getattr__ avanzato def __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
  • 17.
    __getattr__ avanzato def __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 for b in c.find_by_author('Marco Beri'): La facciamo diventare metodo della classe print b for b in c.find_by_author('Alex Martelli'): Ora getattr la può trovare (nella fase 2.) e print b restituisce il metodo
  • 18.
    Server side modules Scriviamoun gestore (“handler”) che contiene il codice per implementare il protocollo Creiamo un server cui passiamo l’handler Il server gestisce i dettagli, noi il protocollo Server prefabbricati: TCPServer ForkingUDPServer UDPServer ThreadingTCPServe r ForkingTCPServer
  • 19.
    Handler Per ogni richiestaviene creato un nuovo handler Alcuni 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...
  • 20.
    Handler (2) Sisottoclassa 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
  • 21.
    Handler (2) Sisottoclassa 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
  • 22.
    import SocketServer class 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_data try: srv = SocketServer.ForkingTCPServer(('', 8881), EchoHandler) srv.serve_forever() except KeyboardInterrupt: print 'Stopping server...'
  • 23.
    Scriviamo Gumball! Scriviamo unsimulatore di macchine che distribuiscono 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 Design Patterns, Freeman&Freeman, O’Reilly
  • 25.
    Il metodo tradizionale classGumballMachine(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 can't 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 can't insert a quarter, the machine is sold out" elif self.state == GumballMachine.SOLD: print "Please wait, we are already giving you a gumball"
  • 26.
    Il metodo tradizionale defeject_quarter(self): if self.state == GumballMachine.HAS_QUARTER: print "Quarter returned" self.state = GumballMachine.NO_QUARTER elif self.state == GumballMachine.NO_QUARTER: print "You haven't inserted a quarter" elif self.state == GumballMachine.SOLD_OUT: print "You can't eject, you haven't 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 doesn't 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()
  • 27.
    Il metodo tradizionale defdispense(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"
  • 28.
    Il metodo tradizionale defdispense(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...
  • 30.
  • 31.
    State pattern eprotocolli Design pattern nei linguaggi dinamici State pattern Vediamo il punto di vista per implementare un protocollo?
  • 32.
    Pattern state Glistati sono rappresentati da oggetti L’oggetto principale “delega” le azioni ai metodi degli stati Eventualmente questi cambiano lo stato Aggiungere stati diventa facile
  • 33.
    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)
  • 34.
    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 can't 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"
  • 35.
    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 haven't 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"
  • 36.
    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 doesn't 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
  • 37.
    class SoldOutState(object): 'No more balls. Sorry guys.' def __init__(self, gumball): self.gumball = gumball def insert_quarter(self): 'Perform quarter insertion' print "You can't insert a quarter, the machine is sold out" def eject_quarter(self): 'Ask the quarter back' print "You can't eject, you haven't 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"
  • 38.
    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
  • 40.
  • 41.
    Web cgi (sconsigliato)/fastcgi WSGI: modulodi medio livello per interfacciarsi con i server Django: framework completo, molto usato Nevow: framework completo basato su Twisted Zope2/3: “mega framework” Google App Engine (+web.py ev. Django) web.py: modulo minimalista, facile comprensione
  • 42.
    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()
  • 43.
    XML-RPC Server from SimpleXMLRPCServerimport SimpleXMLRPCServer from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler class 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 + y server.register_function(adder_function, 'add') class MyFuncs: def div(self, x, y): return x // y server.register_instance(MyFuncs()) server.serve_forever()
  • 44.
    XML-RPC Client importxmlrpclib 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()