2017-02-20 4 views
4

Мне было интересно, можно ли использовать декоратор дескриптора в подклассе.Как использовать декоратор дескриптора в подклассе

class Descriptor(): 
    def __get__(self, instance_obj, objtype): 
     raise Exception('ouch.') 
    def decorate(self, f): 
     print('decorate', f) 
     return f 

class A(): 
    my_attr = Descriptor() 

class B(): 
    @my_attr.decorate 
    def foo(self): 
     print('hey, whatsup?') 

# --> NameError: name 'my_attr' is not defined 

Это, конечно, не работает, так как my_attr не определено в определении класса в B.

Далее я попробовал:

class B(): 
    @A.my_attr.decorate 
    def foo(self): 
     print('hey, whatsup?') 

# --> Exception: ouch. 

Но этот подход вызывает метод дескриптора __get__ (где instance_obj аргумент None) и, следовательно, тест Exception обжигают. Чтобы получить доступ к декоратора можно проверить для instance_obj быть None возвращается при сам дескриптор:

def __get__(self, instance_obj, objtype): 
    if instance_obj is None: 
     return self 
    raise Exception('avoid this') 
# --> decorate <function B.foo at 0x1021dd7b8> 

Это работает! Но разве это правдоподобно или есть способ использовать декоратор в определении класса B?

ответ

4

Вы можете обойти протокол дескриптора в целом путем извлечения исходного объекта из __dict__ отображения класса:

A.__dict__['my_attr'].decorate 

или уборщик, используя vars():

vars(A)['my_attr'].decorate 

Однако синтаксис @ декоратор не позволяет подписки (вам даны только более простые выражения с доступом к атрибутам и один вызов в конце), поэтому вам нужно сначала извлечь словарь :

_A_my_attr = vars(A)['my_attr'] 
@_A_my_attr.decorate 
def foo(self): 
    # ... 

Однако, если вы не должны захватить привязки к классу, то лучше охранять первый аргумент __get__ быть None, как вы обнаружили. Это именно то, что делают объекты или функции property.

+0

Если бы он хотел глобального, мы бы не поместили декоратор внутри класса – JBernardo

Смежные вопросы