【问题标题】:Decorating a class to monitor attribute changes装饰一个类来监控属性变化
【发布时间】:2013-09-19 16:15:47
【问题描述】:

我希望类能够在订阅者的某个属性发生变化时自动向订阅者发送通知。所以如果我要写这段代码:

@ChangeMonitor
class ChangingClass(object):

    def __init__(self, x):
        self.x = x


changer = ChangingClass(5)
print("Going to change x.")
changer.x = 6
print("Going to not change x.")
changer.x = 6
print("End of program")

输出将是:

Going to change x
Old x = 5, new x = 6
Going to not change x.
End of program.

我的问题是如何实现 ChangeMonitor 装饰器类。在上面的示例中,我假设它会打印一行指示属性的更改,但出于有用的目的,它可以向订阅的对象发送通知。

【问题讨论】:

    标签: python decorator python-decorators


    【解决方案1】:

    你必须添加一个__setattr__() method

    def ChangeMonitor(cls):
        _sentinel = object()
        old_setattr = getattr(cls, '__setattr__', None)
        def __setattr__(self, name, value):
            old = getattr(self, name, _sentinel)
            if old not is _sentinel and old != value:
                print "Old {0} = {1!r}, new {0} = {2!r}".format(name, old, value)
            if old_setattr:
                old_setattr(self, name, value)
            else:
                # Old-style class
                self.__dict__[name] = value
    
        cls.__setattr__ = __setattr__
    
        return cls
    

    这也应该处理现有的__setattr__ 钩子。 _sentinel 也用于允许 None 作为旧值。

    演示:

    >>> changer = ChangingClass(5)
    >>> changer.x = 6
    Old x = 5, new x = 6
    >>> changer.x = 6
    >>> # nothing printed
    ...
    >>> changer.x = None
    Old x = 6, new x = None
    >>> changer.x = 6
    Old x = None, new x = 6
    

    【讨论】:

    • 我没有看到使用 _sentinel 或第二个 if 语句。如果我将 _sentinel 排除在外并将“if old_setattr”语句替换为“old_setattr(self, name, value)”,则行为是相同的。你能解释一下吗?无论如何感谢您的帮助,您的帮助很大!
    • 如果您用None 替换哨兵,您将无法判断None 的旧值是否被新值替换。相反,它将与“根本没有旧值”的情况无法区分。我相信旧式类(不是从 object 继承的)没有默认的 __setattr__ 钩子;不过,我现在无法对此进行测试;测试是否找到钩子可能是多余的
    • 我明白你关于哨兵的观点。我检查了没有从对象继承的代码,示例给出了相同的输出,所以我认为 setattr 的测试是多余的。
    猜你喜欢
    • 2019-10-08
    • 2020-11-11
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 2018-04-28
    • 2017-10-05
    • 1970-01-01
    • 2020-06-20
    相关资源
    最近更新 更多