[英]How can a class run some function when any of its attributes are modified?
Is there some general way to get a class to run a function when any of its attributes are modified?当类的任何属性被修改时,是否有一些通用的方法可以让类运行一个函数? I wondered if some subprocess could be running to monitor changes to the class, but maybe there's a way to inherit from
class
and modify some on_change
function that is a part of the Python class, a bit like how the default __repr__
method of a class can be modified.我想知道是否可以运行一些子
on_change
来监视类的更改,但也许有一种方法可以从class
继承并修改一些作为 Python 类一部分的on_change
函数,有点像类的默认__repr__
方法可以被修改。 What would be some sensible approach here?这里有什么明智的方法?
The actual application is not to just do a printout but to update entries in a database that correspond to data attributes of instantiated classes.实际应用不仅仅是打印输出,而是更新数据库中与实例化类的数据属性相对应的条目。
#!/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
You can override the __setattr__
magic method.您可以覆盖
__setattr__
魔术方法。
class Foo:
def on_change(self):
print("changed")
def __setattr__(self, name, value):
self.__dict__[name] = value
self.on_change()
You can override __setattr__
.您可以覆盖
__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)
However, this only detects assignment directly to the attribute.但是,这只检测直接分配给属性。
event.a[1] = 25
is a call to event.a.__setitem__(1, 25)
, so Event
knows nothing about it; event.a[1] = 25
是对event.a.__setitem__(1, 25)
的调用,所以Event
对此一无所知; it is handled entirely by whatever value event.a
resolves to.它完全由
event.a
解析为的任何值处理。
If you don't want the assignments in __init__
to trigger the notifications, call super().__setattr__
directly to avoid invoking your override.如果您不希望
__init__
的赋值触发通知,请直接调用super().__setattr__
以避免调用您的覆盖。
def __init__(self):
super().__setattr__('a', [10, 20, 30])
super().__setattr(__('b', 15)
Recently I developed server side on python, I had to detect changes on lists/dictionary/whatever you want, the library that saved my life is traits
.最近我在 python 上开发了服务器端,我不得不检测列表/字典/任何你想要的变化,拯救我生命的库是
traits
。 I highly recommend it.我强烈推荐它。 you can easly check what changed/removed/added to your attribute.
您可以轻松检查更改/删除/添加到您的属性的内容。
you can read more here .你可以在这里阅读更多。
specifically for your case, the notification chapter is the most relevant专门针对您的情况, 通知章节是最相关的
here's a small snippet I just ran:这是我刚刚运行的一个小片段:
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)
outupts:输出:
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]
hope this helps.希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.