Python观察者模式对象没有属性

2024-10-01 13:41:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试运行“Python基本参考”一书中的一个例子,其中涉及观察者模式,但是属性有一个问题。当AccountObserver执行__del__时,出现错误-Object没有属性“observer”。我不知道代码有什么问题,所以如果有任何帮助我将不胜感激。在

class Account(object):
    def __init__(self, name, balance):
        self.name = name
        self.balance = balance
        self.observers = set()
    def __del__(self):
        for ob in self.observers:
            ob.close()
        del self.observers
    def register(self, observer):
        self.observers.add(observer)
    def unregister(self, observer):
        self.observers.remove(observer)  
    def notify(self):
        for ob in self.observers:
            ob.update()     
    def withdraw(self, amt):
        self.balance -= amt
        self.notify()


class AccountObserver(object):
    def __init__(self, theaccount):
        self.theaccount = theaccount
        self.theaccount.register(self)

    def __del__(self):
        self.theaccount.unregister(self)
        del self.theaccount

    def update(self):
        print("Balance is %0.2f" % self.theaccount.balance)

    def close(self):
        print("Account no longer in use")


a = Account("Ketty", 200000)
a_mama = AccountObserver(a)
a_tata = AccountObserver(a)
a.unregister(a_mama)
a.withdraw(10)

以及输出:

^{pr2}$

Tags: nameinself属性defaccountclassobserver
1条回答
网友
1楼 · 发布于 2024-10-01 13:41:38

当解释器退出时,Python会清除模块。此时,所有实例和类都将被删除,这意味着Account.__del__可以在AccountObserver.__del__之前运行。清除类的顺序取决于全局命名空间字典的顺序,由于使用了random hash seed,全局命名空间字典的顺序是随机的。Account.__del__删除self.observers,因此以后对account.unregister()的任何调用都将引发一个AttributeError。在

您的代码依赖于当模块退出时仍然存在的类和属性。这意味着您可以同时得到KeyError错误(因为a_mama已经被注销),或者{}因为self.observers属性已经被清除(因为Account.__del__清除了它)。在

^{} documentation中有一个很大的警告:

Warning: Due to the precarious circumstances under which __del__() methods are invoked, exceptions that occur during their execution are ignored, and a warning is printed to sys.stderr instead. Also, when __del__() is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the __del__() method may already have been deleted or in the process of being torn down (e.g. the import machinery shutting down). For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants. Starting with version 1.5, Python guarantees that globals whose name begins with a single underscore are deleted from their module before other globals are deleted; if no other references to such globals exist, this may help in assuring that imported modules are still available at the time when the __del__() method is called.

解决方法是使您的__del__方法在遇到此类异常时更加健壮:

def unregister(self, observer):
    try:
        self.observers.remove(observer)  
    except (KeyError, AttributeError):
        # no such observer, or the observers set has already been cleared

相关问题 更多 >