修改类的任何属性后,该类如何运行某些函数?

时间:2019-12-01 17:19:48

标签: python class attributes

在修改其任何属性时,是否有一些通用方法可以使类运行函数?我想知道是否可以运行一些子进程来监视对该类的更改,但是也许有一种方法可以继承class并修改属于Python类的一部分on_change函数,有点像可以修改类的默认__repr__方法。什么是明智的选择呢?

实际的应用程序不只是打印输出,而是更新数据库中与实例化类的数据属性相对应的条目。

#!/usr/bin/env python

class Event(object):
    def __init__(self):
        self.a = [10, 20, 30]
        self.b = 15
    #def _on_attribute_change(self):
    #    print(f'attribute \'{name_of_last_attribute_that_was_changed}\' changed')

event = Event()
event.a[1] = 25
# printout should happen here: attribute 'a' changed
event.a.append(35)
# printout should happen here: attribute 'a' changed
event.c = 'test'
# printout should happen here: attribute 'c' changed

3 个答案:

答案 0 :(得分:2)

您可以覆盖__setattr__魔术方法。

class Foo:

    def on_change(self):
        print("changed")

    def __setattr__(self, name, value):
        self.__dict__[name] = value
        self.on_change()

答案 1 :(得分:1)

您可以覆盖__setattr__

class Event:
    def __init__(self):
        self.a = [10, 20, 30]
        self.b = 15

    def __setattr__(self, attr, value):
        print(f'attribute {attr} changed')
        super().__setattr__(attr, value)

但是,这仅检测到直接 分配给该属性。 event.a[1] = 25是对event.a.__setitem__(1, 25)的调用,因此Event对此一无所知。由event.a解析的任何值完全处理

如果您不希望__init__中的分配触发通知,请直接致电super().__setattr__以避免调用您的替代。

def __init__(self):
    super().__setattr__('a', [10, 20, 30])
    super().__setattr(__('b', 15)

答案 2 :(得分:1)

最近我在python上开发了服务器端,我不得不检测列表/字典/所需内容上的更改,挽救了我生命的库是traits。我强烈推荐它。您可以轻松检查属性中已更改/删除/添加的内容。

您可以阅读更多here

具体针对您的情况,notification这一章最相关

这是我刚运行的一小段代码:

from traits.api import *


class DataHandler(HasTraits):
    a = List([10, 20, 30])
    b = Int(15)


class Event(HasTraits):
    def __init__(self):
        super().__init__()
        self.data_handler = DataHandler()
        self.data_handler.on_trait_change(Event._anytrait_changed)

    @staticmethod
    def _anytrait_changed(obj, name, old, new):
        is_list = name.endswith('_items')
        if is_list:
            name = name[0:name.rindex('_items')]
        current_val = getattr(obj, name)
        if is_list:
            # new handles all the events(removed/changed/added to the list)
            if any(new.added):
                print("{} added to {} which is now {}".format(new.added, name, current_val))
            if any(new.removed):
                print("{} removed from {} which is now {}".format(new.removed, name, current_val))
        else:
            print('The {} trait changed from {} to {} '.format(name, old, (getattr(obj, name))))

e = Event()
e.data_handler.b = 13
e.data_handler.a.append(15)
e.data_handler.a.remove(15)
e.data_handler.a.remove(20)

输出:

The b trait changed from 15 to 13 
[15] added to a which is now [10, 20, 30, 15]
[15] removed from a which is now [10, 20, 30]
[20] removed from a which is now [10, 30]

希望这会有所帮助。