簡體   English   中英

當一個類的任何屬性被修改時,它如何運行某個函數?

[英]How can a class run some function when any of its attributes are modified?

當類的任何屬性被修改時,是否有一些通用的方法可以讓類運行一個函數? 我想知道是否可以運行一些子on_change來監視類的更改,但也許有一種方法可以從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

您可以覆蓋__setattr__魔術方法。

class Foo:

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

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

您可以覆蓋__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)

最近我在 python 上開發了服務器端,我不得不檢測列表/字典/任何你想要的變化,拯救我生命的庫是traits 我強烈推薦它。 您可以輕松檢查更改/刪除/添加到您的屬性的內容。

你可以在這里閱讀更多。

專門針對您的情況, 通知章節是最相關的

這是我剛剛運行的一個小片段:

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]

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM