2014-04-05 11 views
6

Mam doświadczenie w Pythonie (choć całkowicie samoukiem, więc mogę mieć pewne złe nawyki lub nieporozumienia) i próbuję nauczyć się Ruby, aby poszerzyć mój zakres.Metaprogramowanie w Pythonie - dodawanie metody obiektowej

Czytałem przez kilka porównań i widziałem wiele twierdzeń, że "Python nie może wykonać metaprogramowania" (lub, mniej zapalnie, "Python nie może zrobić metaprogramowania po prostu jako Ruby"). Więc odszedłem i szybko przeczytałem o metaprogramowaniu, i odniosłem wrażenie, że jest to, w zasadzie, edycja metod/zachowań waszych klas/obiektów podczas pracy (proszę poprawić mnie, jeśli jestem niepoprawny!).

Miałem wrażenie, że skoro Python jest dynamiczny, nie powinno to stanowić problemu. Jednakże uruchomiony następującą procedurę badania, które nie dają reakcji I Przewidywana

>>> 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) 

że wrażenie, że każdy sposób przedmiot został automatycznie przekazany samego obiektu jako pierwszy argument (stąd stałe wymagania do definiowania metod obiektowych jako (self, [...])). Dlaczego f nie jest przekazywane do hello()?

+0

duplikat http://stackoverflow.com/questions/972/ dodawanie-metody-do-istniejącego-obiektu – spinlok

Odpowiedz

5

Musisz uczynić go instancemethod. Jest klasa do zrobienia tego w module types. To będzie działać:

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

Ah, gotcha. Wywołanie type() na 'f.make_hello_method' i na' f.hello' uczyniło różnicę jasną. Dziękuję Ci! – scubbo

+0

@scubbo: Jeśli chcesz dodać metodę do klasy, a nie tylko jedną instancję, musisz zamiast tego użyć czegoś takiego jak 'setattr (foo," hello ", hello)', które doda go do klasy, wszystkie istniejące wystąpienia, a także wszelkie nowe, które zostały utworzone. – martineau

2

Widząc jak używasz Python 2, można użyć modułu new do tej pracy:

self.hello = new.instancemethod(hello, self, foo) 
Powiązane problemy