2009-11-10 13 views
17

pisałem kod jak tenProblem z tworzenia obiektu wpłacone w Pythonie

>>> class a(object): 
     def __init__(self): 
      self.__call__ = lambda x:x 

>>> b = a() 

Spodziewałem się, że obiekt klasy A powinien być wpłacone obiekt, ale w końcu to nie jest.

>>> b() 

Traceback (most recent call last): 
    File "<pyshell#5>", line 1, in <module> 
     b() 
TypeError: 'a' object is not callable 
>>> callable(b) 
False 

>>> hasattr(b,'__call__') 
True 
>>> 

Nie mogę zrozumieć, dlaczego. Proszę, pomóż mi.

+0

Próbuję zrobić trochę cukru syntatic. Możesz sobie wyobrazić tworzenie tak dynamicznego generatora funkcji. klasy A: B = create_custom_function ("AA") C = create_custom_function ("BB") – kjshim

Odpowiedz

16

Sp Metody ekologiczne są sprawdzane na typu (np. klasa) obiektu, na którym operuje się, a nie na konkretnym przykładzie. Pomyśl o tym: w przeciwnym razie, jeśli klasa definiuje na przykład __call__, gdy klasa nazywa się, że __call__ powinno zostać wywołane ... co za katastrofa! Ale na szczęście specjalna metoda jest zamiast tego spojrzeniem na typ klasy, metaklasa AKA, i wszystko jest w porządku ("klasy spuścizny" miały bardzo nieregularne zachowanie, dlatego wszyscy jesteśmy lepsi od tych w nowym stylu - które są jedynymi pozostawionymi w Pythonie 3).

Więc jeśli potrzebujesz "nadpisywania instancji" metod specjalnych, musisz upewnić się, że instancja ma własną unikalną klasę. To bardzo proste:

class a(object): 
    def __init__(self): 
     self.__class__ = type(self.__class__.__name__, (self.__class__,), {}) 
     self.__class__.__call__ = lambda x:x 

i jesteś tam. Oczywiście w tym przypadku byłoby to głupie, ponieważ każda instancja kończy się na tej samej "tak zwanej instancji" (!) __call__, ale przydałaby się sytuacja, gdy naprawdę potrzebowałeś nadpisywania dla poszczególnych instancji .

+0

Wow! To był problem między nową i staroświecką metodą. Dziękuję za sprytny sposób na przesłonięcie tego – kjshim

+0

@kjshim, nie ma za co, ale nie jest to specjalnie sprytne, tylko standardowy sposób w Pythonie ;-). –

12

__call__ musi być zdefiniowana na klasie, nie instancja

class a(object): 
    def __init__(self): 
     pass 
    __call__ = lambda x:x 

ale większość osób prawdopodobnie bardziej czytelne określenie metody zwykły sposób

class a(object): 
    def __init__(self): 
     pass 
    def __call__(self): 
     return self 

Jeśli trzeba mieć inne zachowanie dla każdej instancji można to zrobić w ten sposób:

class a(object): 
    def __init__(self): 
     self.myfunc = lambda x:x 

    def __call__(self): 
     return self.myfunc(self) 
+0

Co jeśli chce utworzyć odróżnieniu od instancji wywoływalnego funkcję wykonywania? Czy możesz dać mi sugestywny sposób na to? Dzięki za odpowiedź. – kjshim

+0

i odniosłem się do tego artykułu: http://code.activestate.com/recipes/52304/ – kjshim

1

Co z tym? Definiowanie klasy bazowej AllowDynamicCall:

class AllowDynamicCall(object): 
    def __call__(self, *args, **kwargs): 
     return self._callfunc(self, *args, **kwargs) 

A potem podklasy AllowDynamicCall:

class Example(AllowDynamicCall): 
    def __init__(self): 
     self._callfunc = lambda s: s 
Powiązane problemy