[英]python class decorator inside method
I try to use decorator pattern for class hierarchy, so I define class decorator as below: 我尝试将装饰器模式用于类层次结构,因此我如下定义了类装饰器:
def delegate(cls, target='_base'):
class Wrapper(object):
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
if hasattr(self.wrapped, name):
return getattr(self.wrapped, name)
else:
return getattr(self.wrapped.__dict__.get(target), name)
return Wrapper
class A(object):
def __init__(self):
pass
def foo(self):
print('this is foo()')
@delegate
class B(object):
def __init__(self):
self._base = A()
def bar(self):
self.foo() # self._base.foo() will work
def main():
B().foo() #1. works
B().bar() #2. attribute not found error
Why does the call to self.foo() inside bar() doesn't go throw delegate while #1 works? 为什么在#1起作用时,对bar()中的self.foo()的调用没有抛出委托? To solve it with decorator without hardcode self._base.foo(), must I write method decorator for each method need _base inside B? 为了用没有硬性代码self._base.foo()的装饰器解决它,我是否必须为B中需要_base的每个方法编写方法装饰器? I try to cut down the boilerplate code. 我尝试减少样板代码。
def delegate(cls, target='_base'):
class Wrapper(object):
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
if hasattr(self.wrapped, name):
return getattr(self.wrapped, name)
else:
return getattr(self.wrapped.__dict__.get(target), name)
return Wrapper
class A(object):
def __init__(self):
pass
def foo(self):
print('this is foo()')
@delegate
class B(object):
def __init__(self):
self._base = A()
def bar(self):
self.foo()
def thirdbar(self):
self._base.foo() # self._base.foo() will work
def secondbar(self,x):
x.foo() # self._base.foo() will work
x=B()
x.foo() #1. works
x.secondbar(x) #it is working
x.thirdbar() #it is working
x.bar() #still not working
This is happening because the behavior of decorators is (at least to me) somewhat counterintuitive. 之所以发生这种情况,是因为装饰器的行为(至少对我而言)有点违反直觉。
Here's what happens when you check the types of all the objects involved: 当您检查所有涉及的对象的类型时,将发生以下情况:
>>> type(b)
<class 'Wrapper'>
>>> type(b.wrapped)
<class 'B'>
>>> type(b.wrapped._base)
<class 'A'>
Because b
is really an instance of Wrapper
and not B
, when you call b.foo()
, what's happening is (psuedocode): 因为b
实际上是Wrapper
的实例,而不是 B
,所以当您调用b.foo()
,发生的是(psuedocode):
b.foo() --> Wrapper.__getattr__(foo) --> wrapped._base.foo
So foo
is coming from the Wrapper
object's __getattr__
-- not the Bar
object's. 因此foo
来自Wrapper
对象的__getattr__
而不是Bar
对象的。
The problem is that in defining bar
this way: 问题在于以这种方式定义bar
:
def bar(self):
self.foo()
self
does not refer to the Wrapper
object's foo
attribute, but the Bar
object's foo attribute, which doesn't exist. self
不引用Wrapper
对象的foo
属性,而是Bar
对象的foo属性,该属性不存在。
So, when you call b.bar()
the method chain is: 因此,当您调用b.bar()
,方法链为:
b.bar() --> Wrapper.__getattr__(bar) --> wrapped.bar() --> wrapped.foo()
You can fix this by having Bar
invoke self._base.foo()
. 您可以通过让Bar
调用self._base.foo()
来解决此问题。
B().bar() #2. attribute not found error
Why? 为什么? You instantiate the Wrapper
which instantiates the wrapped
. 实例化Wrapper
该实例的wrapped
。
You then do a dotted lookup of 'bar'
. 然后,您可以对'bar'
进行点分查找。
'bar'
will be found in the wrapped B
, so this returns a bound method, self
being the wrapped B()
, not the Wrapper()
: 'bar'
将在包装好的B
找到,因此这将返回一个绑定方法, self
就是包装的B()
,而不是Wrapper()
:
def __getattr__(self, name):
if hasattr(self.wrapped, name):
return getattr(self.wrapped, name)
I'm not sure what you're trying to accomplish here. 我不确定您要在这里完成什么。 It seems that subclassing or adding the behavior directly to the class may be preferable to doing this. 似乎将子类化或直接将行为添加到类中可能比这样做更好。
It is said that you have to be twice as clever to debug code as to write it. 据说调试代码的技巧必须是编写代码的两倍。 If you're being too clever, you're making it impossible for you to debug it. 如果您太聪明了,那么就使您无法调试它。 I would suggest doing something different here. 我建议在这里做些不同的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.