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

抽象工厂模式与委托模式结合出现RecursionError的原因及解决方法

问题:结合抽象工厂与委托模式时触发RecursionError

我在Python中学习设计模式,尝试结合抽象工厂模式与委托模式加深理解,但遇到了无法解决的RecursionError,错误信息如下:

[Previous line repeated 987 more times]
  File "c:\Users\jenny\Documents\design_pattern\creational\abstract_factory.py", line 60, in __getattribute__
    def __getattribute__(self, name: str):

RecursionError: maximum recursion depth exceeded 

该错误在调用client_with_laptop.display()时触发,甚至在__init__阶段,client_with_laptop._hardware就已经存在递归问题。

相关完整代码如下:

from abc import abstractmethod


class ITechnique:
    # 抽象产品
    @abstractmethod
    def display(self):
        pass

    def turn_on(self):
        print("I am on!")

    def turn_off(self):
        print("I am off!")


class Laptop(ITechnique):
    # 具体产品
    def display(self):
        print("I'am a Laptop")

class Smartphone(ITechnique):
    # 具体产品
    def display(self):
        print("I'am a Smartphone")

class Tablet(ITechnique):
    # 具体产品
    def display(self):
        print("I'm a tablet!")


class IFactory:
    @abstractmethod
    def get_hardware():
        pass

class SmartphoneFactory(IFactory):
    def get_hardware(self):
        return Smartphone()


class LaptopFactory(IFactory):
    def get_hardware(self):
        return Laptop()

class TabletFactory(IFactory):
    def get_hardware(self):
        return Tablet()


class Client():
    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

    def __getattribute__(self, name: str):
        return getattr(self._hardware, name)

if __name__ == "__main__":
    client_with_laptop = Client(LaptopFactory())
    client_with_laptop.display()

    client_with_tablet = Client(TabletFactory())
    client_with_tablet.display()

    client_with_smartphone = Client(SmartphoneFactory())
    client_with_smartphone.display()

移除__getattribute__(委托模式实现部分)后,直接访问_hardware代码可正常运行,修改后的代码片段:

class Client():
    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

if __name__ == "__main__":
    client_with_laptop = Client(LaptopFactory())
    client_with_laptop._hardware.display()

    client_with_tablet = Client(TabletFactory())
    client_with_tablet._hardware.display()

    client_with_smartphone = Client(SmartphoneFactory())
    client_with_smartphone._hardware.display()

我的目标是:

  • 根据Client使用的工厂生成对应设备;
  • 无需输入client._hardware,直接通过Client对象调用_hardware的方法(如client.display())。

错误原因

问题出在Client类的__getattribute__方法上:

  • Python中,访问任何实例属性或方法都会触发__getattribute__,包括你在方法内部访问self._hardware的时候。
  • 当你在__getattribute__里写self._hardware,会再次调用当前类的__getattribute__方法,试图获取_hardware属性,这就形成了无限递归,最终触发递归深度超限错误。

修复方法

有两种可靠的修复方式,都能实现你要的委托效果:

方法1:使用super().__getattribute__获取_hardware

通过调用父类(object)的__getattribute__方法来获取_hardware,绕开当前类的递归调用:

class Client():
    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

    def __getattribute__(self, name: str):
        # 先通过父类方法获取_hardware,避免递归
        hardware = super().__getattribute__('_hardware')
        return getattr(hardware, name)

方法2:改用__getattr__方法

__getattr__只会在访问的属性/方法不存在于当前实例时才会被调用,不会影响已有属性(比如_hardware)的正常访问,天然避免递归问题:

class Client():
    def __init__(self, factory: IFactory) -> None:
        self._hardware = factory.get_hardware()

    def __getattr__(self, name: str):
        # 只有当Client实例本身没有该属性时,才委托给_hardware
        return getattr(self._hardware, name)

两种方法都能让你直接通过client.display()调用设备的方法,同时保持抽象工厂模式的功能。


内容的提问来源于stack exchange,提问作者JKupzig

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:53:22