You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:20:41