如何在子 class 中使用描述符的装饰器
How to use a decorator of a descriptor within a sub class
我想知道是否可以在子class 中使用描述符的装饰器。
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 定义中未定义。
接下来我尝试了:
class B():
@A.my_attr.decorate
def foo(self):
print('hey, whatsup?')
# --> Exception: ouch.
但是,此方法调用描述符 __get__
方法(其中 instance_obj
参数为 None
),因此会触发测试异常。要访问装饰器,可以检查 instance_obj
是 None
还是 return 描述符本身:
def __get__(self, instance_obj, objtype):
if instance_obj is None:
return self
raise Exception('avoid this')
# --> decorate <function B.foo at 0x1021dd7b8>
有效!但这是否合理,或者有没有办法在 B
的 class 定义中使用装饰器?
您可以通过从 class 的 __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):
# ...
但是,除非您必须捕获到 class 的绑定,否则最好注意 __get__
的第一个参数是 None
,正如您发现的那样。这正是 property
对象或函数所做的。
我想知道是否可以在子class 中使用描述符的装饰器。
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 定义中未定义。
接下来我尝试了:
class B():
@A.my_attr.decorate
def foo(self):
print('hey, whatsup?')
# --> Exception: ouch.
但是,此方法调用描述符 __get__
方法(其中 instance_obj
参数为 None
),因此会触发测试异常。要访问装饰器,可以检查 instance_obj
是 None
还是 return 描述符本身:
def __get__(self, instance_obj, objtype):
if instance_obj is None:
return self
raise Exception('avoid this')
# --> decorate <function B.foo at 0x1021dd7b8>
有效!但这是否合理,或者有没有办法在 B
的 class 定义中使用装饰器?
您可以通过从 class 的 __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):
# ...
但是,除非您必须捕获到 class 的绑定,否则最好注意 __get__
的第一个参数是 None
,正如您发现的那样。这正是 property
对象或函数所做的。