2010-03-02 7 views
50

To jest python 2.5, to jest GAE też nie, że to ma znaczenie.Zdobywając metody klasy Pythona, w jaki sposób przekazać instancję do dekoratora?

Mam następujący kod, jestem dekorowanie metody foo() w bar, przy użyciu klasy dec_check jako dekorator.

class dec_check(object): 

    def __init__(self, f): 
    self.func = f 

    def __call__(self): 
    print 'In dec_check.__init__()' 
    self.func() 

class bar(object): 

    @dec_check 
    def foo(self): 
    print 'In bar.foo()' 

b = bar() 
b.foo() 

Podczas wykonywania tego miałem nadzieję zobaczyć:

In dec_check.__init__() 
In bar.foo() 

Ale ja dostaję „TypeError: foo() takes exactly 1 argument (0 given)” jako .foo(), jako metoda obiektu, bierze siebie jako argument. Zgaduję, że problem polega na tym, że instancja bar faktycznie nie istnieje, gdy wykonuję kod dekoratora.

Jak przekazać instancję klasy bar do klasy dekoratora?

Odpowiedz

70

Trzeba zrobić dekorator do descriptor - albo poprzez zapewnienie jej (meta) klasa ma __get__ metody, lub, sposób prostszy, za pomocą dekoratora funkcję zamiast dekorator klasa (ponieważ funkcje są już deskryptorami). Np .:

def dec_check(f): 
    def deco(self): 
    print 'In deco' 
    f(self) 
    return deco 

class bar(object): 
    @dec_check 
    def foo(self): 
    print 'in bar.foo' 

b = bar() 
b.foo() 

to drukuje

In deco 
in bar.foo 

to pożądane.

+1

Zmień linię 'f (self) na' return f (self) ', aby przekazać zwrot' foo' z powrotem do osoby dzwoniącej. – j6m8

+0

Zepsuty link do strony deskryptora. – Apteryx

43

Odpowiedź Alex wystarczy, gdy funkcja jest wystarczająca. Jednak gdy potrzebujesz klasy, możesz sprawić, by działała, dodając następującą metodę do klasy dekoratora.

def __get__(self, obj, objtype): 
    """Support instance methods.""" 
    import functools 
    return functools.partial(self.__call__, obj) 

Aby to zrozumieć, należy zrozumieć protokół deskryptora. Protokół deskryptora jest mechanizmem wiązania rzeczy z instancją. Składa się z __ get __, __ set __ i __ delete __, które są wywoływane, gdy rzecz jest ustawiona, lub usunięta ze słownika instancji. W tym przypadku, gdy rzecz pochodzi z instancji, wiążemy pierwszy argument jego metody __ call do instancji, używając częściowego. Robi się to automatycznie dla funkcji składowych, gdy klasa jest konstruowana, ale dla funkcji syntetycznego elementu, takiej jak ta, musimy to zrobić jawnie.

+4

Wydaje się to działać. Czy możesz wyjaśnić, jak to działa? – Gilbert

+6

@ Gilbert Protokół deskryptora jest mechanizmem wiązania rzeczy z instancją. Składa się z __ get __, __ set __ i __ delete __, które są wywoływane, gdy rzecz jest ustawiona, lub usunięta ze słownika instancji.W tym przypadku, gdy rzecz pochodzi z instancji, wiążemy pierwszy argument jego metody __ call do instancji, używając częściowego. Robi się to automatycznie dla funkcji składowych, gdy klasa jest konstruowana, ale dla funkcji syntetycznego elementu, takiej jak ta, musimy to zrobić jawnie. –

+3

A co z tym, że dekorator bierze argumenty? –

0

jeśli chcesz napisać dekoratora jako klasę, którą możesz zrobić.

from functools import update_wrapper, partial 

MyDecorator(object): 
    def __init__(self, func): 
     update_wrapper(self, func) 
     self.func = func 

    def __get__(self, obj, objtype): 
     """Support instance methods.""" 
     return functools.partial(self.__call__, obj) 

    def __call__(self, obj, *args, **kwargs): 
     print('Logic here') 
     return self.func(obj, *args, **kwargs) 

my_decorator = MyDecorator 

class MyClass(object): 
    @my_decorator 
    def my_method(self): 
     pass 
Powiązane problemy