是否可以在python中装饰__setatr__方法?

时间:2019-07-19 20:43:54

标签: python

当对象的内容更改时,我试图触发一个函数。我试图通过装饰python中的 setattr 方法来执行此操作,因为使用=运算符时会调用此方法。

我尝试使用@decorator装饰 setattr 函数,并且此方法有效,但是我想尝试在运行时装饰它,以便我可以按对象的每个实例装饰它。到目前为止,我已经尝试了下面的代码。

class TestObject:
    pass

def on_object_change(func):
    def wrapper(*args, **kwargs):
        print("value changed %s - %s" % (args, kwargs))
        func(*args, **kwargs)
    return wrapper

obj = TestObject()
wrapper = on_object_change(obj.__setattr__)
obj.__setattr__ = wrapper

obj.one = 1
obj.__setattr__("two", 2)
setattr(obj, "three", 3)

我希望输出为:

值已更改(“ one”,1)-{}

值已更改(“ two”,2)-{}

值已更改(“三”,3)-{}

但是实际输出是:

值已更改(“ two”,2)-{}

obj的内容已更改为1、2和3。但是没有调用包装函数。我只是想知道这是否是预期的行为。如果还有另一种装饰 setattr 功能的方法。

3 个答案:

答案 0 :(得分:0)

更改代码以装饰类的方法,而不是对象的方法

class TestObject:
    pass

def on_object_change(func):
    def wrapper(*args, **kwargs):
        print("value changed %s - %s" % (args[1:], kwargs))
        func(*args, **kwargs)
    return wrapper

wrapper = on_object_change(TestObject.__setattr__)          
TestObject.__setattr__ = wrapper

现在,以下设置操作将导致以下提到的输出

obj = TestObject()
obj.one = 1
obj.__setattr__("two", 2)
setattr(obj, "three", 3)

输出

value changed ('one', 1) - {}
value changed ('two', 2) - {}
value changed ('three', 3) - {}

答案 1 :(得分:0)

如果要使用装饰器,为什么不使用decorator syntax

def on_object_change(func):
    def wrapper(*args, **kwargs):
        print("value changed %s - %s" % (args, kwargs))
        func(*args, **kwargs)
    return wrapper

class TestObject:

    @on_object_change
    def __setattr__(self, *args, **kwargs):
        super().__setattr__(*args, **kwargs)

obj = TestObject()
obj.one = 1
obj.__setattr__('two', 2)
setattr(obj, 'three', 3)

打印:

value changed (<__main__.TestObject object at 0x7f38da0f3b70>, 'one', 1) - {}
value changed (<__main__.TestObject object at 0x7f38da0f3b70>, 'two', 2) - {}
value changed (<__main__.TestObject object at 0x7f38da0f3b70>, 'three', 3) - {}

答案 2 :(得分:0)

我发现了一些问题

def on_object_change(func):
    def wrapper(item, value):
        print("value changed %s - %s" % (item, value))
        func(item, value)
    return wrapper

class TestObject:
    def setattr(key, value):
        super().__setattr__(key, value)

    def __setattr__(self, key, value):
        self.setattr(key, value)

obj = TestObject()
obj2 = TestObject()

obj.setattr = on_object_change(obj.setattr)

obj.one = 1
obj2.two = 2

由于 setattr 方法已绑定到该类,因此无法针对每个实例执行此操作。通过在这两个函数之间添加的桥梁,可以为每个TestObject实例添加一个包装器。

output obj.one = 1 -> value changed one - 1
output obj2.two = 2 -> 

这正是我所需要的。