我可以在python中装饰一个`__getattr__`方法吗?

时间:2017-05-16 10:09:47

标签: python python-3.x python-decorators

是否可以在python中装饰像__getattr__这样的方法?

喜欢这个

@myWrapper
def __getattr__(self,attrName):
    '''
    myCode Goes here
    '''

当我尝试使用上述内容时,我遇到了一些错误:

感谢willem指出..

我发现了我在代码中犯的错误。

我打算做这样的事情

class A:
    def __init__(self):
        self.a=someObject()
    @mywrapper
    def __getattr__(self,argName):
        # call self.a 's  method. If that doesnt have
        # then raise an exception

所以我的方法可能有一些参数,我也需要传递它..

所以我写了这样的东西来测试:

class A:
    def __init__(self):
        self.a=someObject()
    @mywrapper
    def __getattr__(self,argName):
        print('getAttr called for {}'.format(argName))
        def mymethod(*args,**kwargs):
            import ipdb;ipdb.set_trace()
        return mymethod

我的包装器代码如下所示:

def mywrapper(method):
    def methodWrapper(obj,name):
        print("In decorator for {}".format(method));
        method(obj,name)
    return methodWrapper

但是当我像obj.c(1)一样执行时,我得到以下异常

TypeError: 'NoneType' object is not callable

事实上,装饰器和__getattr__中的print语句都已执行但我看到异常..

如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

是的,这是可能的。 __getattr__实际上只是另一个函数,尽管Python解释器会将其称为回退机制之一。关于__init____getattr__等没有任何固有的特殊内容。

按照惯例,带有前导和尾部双下划线的名称是“magic”对象或属于用户控制的命名空间的属性。例如。 __init____import____file__。不要发明这样的名字;只能按照记录的方式使用它们。“。但这是风格指南(你最好遵循)。

出于某种原因,您的@myWrapper 不尊重(数量)属性

例如,如果您要写一个包装器:

def myWrapper(func):
    def g(self,attrName):
        return func(self,'foo_%s'%attrName)
    return g

然后有没有问题。

如果我们现在定义一个类Foo

class Foo:

    @myWrapper
    def __getattr__(self,attrName):
        print(attrName)

然后我们看到装饰器正常工作:

>>> foo = Foo()
>>> foo.bla
foo_bla

正如您所见,__getattr__打印foo_bla,这意味着myWrapper已将该属性添加到foo_之前。

至于你的(编辑过的)问题,我想它之所以说“TypeError:'NoneType'对象不可调用”是因为装饰者应返回一个(新)函数

可能你的装饰师看起来像:

def mywrapper(func):
    def g(self,attrName):
        return func(self,attrName)

所以你可能忘了拨打return g

编辑:根据您更新的问题,问题是您返回内部__getattr__电话的结果:

def mywrapper(method):
    def methodWrapper(obj,name):
        print("In decorator for {}".format(method));
        return method(obj,name) -- with a return statement
    return methodWrapper

这很重要,因为__getattr__ 会返回一个函数。请注意,在mywrapper的上下文中,method原始 __getattr__methodWrapper是新__getattr__。所以你应该传递原始__getattr__的结果。现在你不用它做任何事情并返回(默认情况下)None