2012-06-22 17 views
6

Sono confuso su questo comportamento portata:strano comportamento portata funzione Python

class Bar: 
    def __init__(self): 
     for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]: 
      print "register", fn 
      def func_wrapper(filename): 
       print "called func wrapper", fn, filename 
      setattr(self, fn, func_wrapper) 

bar = Bar() 
bar.open("a") 
bar.remove("b") 
bar.listdir("c") 

Questo dà l'output:

register open 
register openW 
register remove 
register mkdir 
register exists 
register isdir 
register listdir 
called func wrapper listdir a 
called func wrapper listdir b 
called func wrapper listdir c 

Ma mi sarei aspettato che func_wrapper sarebbe sempre il corretto funzionamento. So che l'ambito di func_wrapper riguarda l'intera funzione, ma lo ridefinisco in ogni iterazione del ciclo e l'ultima istanza è stata salvata nell'attrib. Ho anche provato ad aggiungere func_wrapper = None sotto lo setattr ma questo non aiuta (mi avrebbe anche chiesto ...).

Sono cieco? Non vedo nemmeno davvero come aggirare/risolvere questo problema.

+0

@heltonbiker: puoi elaborare? Come dovrei usare un dict invece qui? E perché? – Albert

+0

Ho letto più a fondo e ho eliminato il commento precedente. – heltonbiker

risposta

6

O con

class Bar: 
    def __init__(self): 
     for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]: 
      print "register", fn 
      def func_wrapper(filename, fn=fn): 
       print "called func wrapper", fn, filename 
      setattr(self, fn, func_wrapper) 

o, più robusta, con

def mkwrapper(fn): 
    def func_wrapper(filename): 
     print "called func wrapper", fn, filename 
    func_wrapper.__name__ = fn 
    return func_wrapper 

class Bar: 
    def __init__(self): 
     for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]: 
      print "register", fn 
      func_wrapper = mkwrapper(fn) 
      setattr(self, fn, func_wrapper) 

Nel tuo esempio originale, tutte le funzioni generate accedere alla stessa variabile esterna fn, che cambia in ogni corsa loop. Negli esempi corretti, questo è impedito.

+0

Ah sì, ho pensato a sth come questo ... :) – Albert

+0

Ho sempre pensato che ci fosse qualcosa di * speciale * su 'lambda' per quanto riguarda l'associazione tardiva, ma ora capisco che le funzioni regolari hanno davvero lo stesso problema, è solo che non vengono utilizzati così spesso allo stesso modo delle funzioni lambda. +1 per domande e risposte. –

+0

Vorrei davvero che la gente smettesse di raccomandare quel parametro predefinito. –