Python类装饰" self"似乎错了

时间:2018-05-16 06:51:50

标签: python python-decorators class-decorator

我正在尝试弄清楚如何使用类上的装饰器来更改类的__setattr__的功能,但是在尝试访问替换的函数内的self时遇到问题__setattr__。如果我将问题专栏更改为不访问self,例如用val = str(val)替换它,我得到了预期的行为。

我在这里看到其他问题中的类似问题,但他们使用不同的方法,其中一个类被用作decorater。我的下面的方法感觉不那么复杂,所以如果可能的话我会喜欢这样做。

为什么a / self无法定义foo

# Define the function to be used as decorator
# The decorator function accepts the relevant fieldname as argument
# and returns the function that wraps the class
def field_proxied(field_name):

    # wrapped accepts the class (type) and modifies the functionality of
    # __setattr__ before returning the modified class (type)
    def wrapped(wrapped_class):
        super_setattr = wrapped_class.__setattr__

        # The new __setattr__ implementation makes sure that given an int,
        # the fieldname becomes a string of that int plus the int in the
        # `a` attribute
        def setattr(self, attrname, val):
            if attrname == field_name and isinstance(val, int):
                val = str(self.a + val)  # <-- Crash. No attribute `a`
                super_setattr(self, attrname, val)
        wrapped_class.__setattr__ = setattr
        return wrapped_class
    return wrapped

@field_proxied("b")
class Foo(object):
    def __init__(self):
        self.a = 2
        self.b = None

foo = Foo()
# <-- At this point, `foo` has no attribute `a`
foo.b = 4
assert foo.b == "6"  # Became a string

1 个答案:

答案 0 :(得分:1)

问题很简单,你只需要换一行。

def setattr(self, attrname, val):
    if attrname == field_name and isinstance(val, int):
        val = str(self.a + val)
    super_setattr(self, attrname, val)  # changed line

原因是,在原始方法中,您只能在super_setattr时拨打attrname == field_name。因此self.a = 2中的__init__根本不起作为"a" != "b"