简体   繁体   English

python类装饰器内部方法

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM