2014-04-05 11 views
6

Ho uno sfondo in Python (anche se completamente autodidatta, quindi potrei avere alcune cattive abitudini o idee sbagliate) e sto cercando di imparare Ruby per ampliare il mio ambito.Metaprogramming in Python - aggiunta di un metodo oggetto

Stavo leggendo alcuni confronti, e ho visto molte asserzioni che "Python non può fare metaprogrammazione" (o, meno infiammatoriamente, "Python non può fare metaprogrammazione così semplicemente come Ruby"). Così sono andato via e ho letto velocemente sulla metaprogrammazione, e ho avuto l'impressione che, in pratica, modifichi i metodi/comportamenti delle classi/oggetti durante il runtime (per favore correggimi se sono errato!).

Ho avuto l'impressione che, dal momento che Python è dinamico, non dovrebbe essere un problema. Tuttavia, ho eseguito il seguente codice di prova, che non ha dato la risposta che aspettavo:

>>> class foo: 
...  def make_hello_method(self): 
...    def hello(obj): 
...      print 'hello' 
...    self.hello = hello 
... 
>>> f = foo() 
>>> f.hello() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: foo instance has no attribute 'hello' 
>>> f.make_hello_method() 
>>> f.hello() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: hello() takes exactly 1 argument (0 given) 

ero sotto l'impressione che ogni metodo di un oggetto è stato passato automaticamente l'oggetto stesso come primo argomento (da cui il requisiti costanti per definire i metodi dell'oggetto come (self, [...])). Come mai f non viene passato a hello()?

+0

duplicati di http://stackoverflow.com/questions/972/ aggiunta-un-metodo-a-un-oggetto-esistente – spinlok

risposta

5

È necessario renderlo un instancemethod. C'è una classe per farlo nel modulo types. Ciò funzionerà:

self.hello = types.MethodType(hello, self) 
+0

Ah, gotcha. Chiamare type() su 'f.make_hello_method' e su' f.hello' ha chiarito la differenza. Grazie! – scubbo

+0

@scubbo: se si desidera aggiungere il metodo alla classe anziché solo l'istanza, è necessario utilizzare invece qualcosa come 'setattr (foo," ciao ", ciao)', che lo aggiungerebbe alla classe, tutte le istanze esistenti e tutte le nuove create. – martineau

2

Visto che si sta utilizzando Python 2, è possibile utilizzare il modulo new per fare questo lavoro:

self.hello = new.instancemethod(hello, self, foo) 
Problemi correlati