简体   繁体   English

当一个类的任何属性被修改时,它如何运行某个函数?

[英]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.

相关问题 函数如何访问自己的属性? - How can a function access its own attributes? 是否可以创建一个在修改时实现其所有属性的对象? - Is it possible to create an object that actualize all its attributes when modified? NeuralNetwork类无法访问其属性 - NeuralNetwork class can't access its attributes 函数在类中的属性 - Function's attributes when in a class 有什么办法可以限制孩子 class 继承其父母的某些方法吗? - Is there any way that I can restrict a child class from inheriting some of its parent's methods? 如何从另一个类运行函数并使用其变量? - How To Run A Function From Another Class & Use Its Variable? 如何确保每个子类都获得其父类属性的最新副本(在Python中)? - How can I ensure that every child class gets a fresh copy of its parent's class attributes (in Python)? 我如何封装 class 的私有可变 object,以便它可以通过不可变的 object 公开其属性? - How can I encapsulate a private mutable object of a class such that it can expose its attributes publicly through an inmutable object? 如果没有 Django 中的“parent.attrib”语法,子 class 如何访问其父属性? - How can a child class access its parent attributes without the “parent.attrib” syntax in Django? 如何从其属性之一的值检索类的实例? - How can I retrieve the instance of a class from a value of one of its attributes?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM