Python中self参数引用异常与观察者模式实现报错求助
问题排查与优化建议
错误原因分析
你遇到的AttributeError: 'str' object has no attribute 'ObserverList'主要由以下几个问题导致:
实例方法参数顺序错误
Subject类的notifyObservers方法参数顺序搞反了,Python实例方法的第一个参数必须是self(指向当前实例),你写成了def notifyObservers(message, self):,调用时传入的字符串会被当成self,此时访问self.ObserverList自然报错(因为self是字符串类型)。重复创建Subject实例
每次调用Newsletter()都会生成全新的Subject对象,添加观察者、通知观察者用的都是不同实例,导致观察者根本没被加入同一个实例的列表,通知时也找不到目标。观察者实例创建错误
你把ConcreteStateA模块直接赋值给Paul、Sara等变量,而不是创建类的实例,正确做法应该是生成类的实例,比如Paul = Obs.ConcreteStateA()。观察者方法不匹配
观察者类定义的是Handle方法,但Subject的notifyObservers里调用的是obs.update(message),方法名不匹配;同时Handle的参数顺序也错了,应该是self在前、消息在后。
修复后的完整代码
1. Observer抽象类(新建Observer.py)
from abc import ABC, abstractmethod class Observer(ABC): @abstractmethod def update(self, message): pass
2. Subject类(Subject.py)
class Subject: def __init__(self): self.observer_list = [] # 改用小写蛇形命名,符合Python规范 def add_observer(self, observer): self.observer_list.append(observer) def remove_observer(self, observer): if observer in self.observer_list: # 先判断存在再移除,避免ValueError self.observer_list.remove(observer) def notify_observers(self, message): # 修正参数顺序,self放第一位 print("开始通知所有观察者...") for obs in self.observer_list: obs.update(message)
3. 具体观察者类(ConcreteObserverA.py,原类名改名以符合模式语义)
import Observer class ConcreteObserverA(Observer.Observer): def __init__(self, name): self.name = name # 初始化时传入观察者名字 def update(self, message): # 统一为update方法,参数顺序正确 print(f"{self.name} 收到消息: {message}")
4. 主程序代码
import Subject as Subj import ConcreteObserverA as Obs # 创建唯一的Subject实例 newsletter = Subj.Subject() # 创建观察者实例并传入名字 paul = Obs.ConcreteObserverA("Paul") sara = Obs.ConcreteObserverA("Sara") julien = Obs.ConcreteObserverA("Julien") # 向同一个Subject实例添加观察者 newsletter.add_observer(paul) newsletter.add_observer(sara) newsletter.add_observer(julien) # 第一次通知 newsletter.notify_observers("圣诞快到了!") # 移除Paul后再次通知 newsletter.remove_observer(paul) newsletter.notify_observers("圣诞老人就在门外!")
优化建议
- 遵循Python命名规范:类名用大驼峰(如
ConcreteObserverA),变量和方法名用小写蛇形(如observer_list、add_observer),避免与内置名称冲突,提升代码可读性。 - 添加边界判断:移除观察者时先判断是否在列表中,避免出现
ValueError。 - 用抽象基类约束观察者:通过
ABC和abstractmethod强制所有观察者实现update方法,避免漏写方法导致的错误。 - 确保Subject实例唯一:所有操作针对同一个Subject实例,否则观察者和通知逻辑会失效。
- 类名语义化:原
ConcreteStateA易混淆状态模式与观察者模式,改名ConcreteObserverA更清晰。
内容的提问来源于stack exchange,提问作者Buschmxnn
相关产品推荐
相关产品推荐

