如何修改基类来动态实例化适当的子类而不引起递归?

问题描述 投票:0回答:1

我正在重构一个Python类结构,之前我直接实例化子类,但现在我想转向一种仅调用基生成器类的设计,并且该基类在内部决定并返回适当的子类实例。但是,我在这种新方法中遇到了递归问题。我的代码是:

class BaseGenerator:
    def __new__(cls, *args, **kwargs):
        if cls is BaseGenerator:
            subclass = cls._determine_subclass(*args, **kwargs)
            return subclass(*args, **kwargs)
        else:
            return super().__new__(cls)

    @staticmethod
    def _determine_subclass(*args, **kwargs):
        # Logic to determine the appropriate subclass
        # ...

class ChildGenerator1(BaseGenerator):
    pass

class ChildGenerator2(BaseGenerator):
    pass

class ChildGenerator3(BaseGenerator):
    pass

最初,我有一个包含一个基本生成器类 (BaseGenerator) 和几个子类(ChildGenerator1、ChildGenerator2、ChildGenerator3)的结构。我曾经像这样直接实例化这些子类:

generator = ChildGenerator1(...)

现在,我只想使用 BaseGenerator 来决定并实例化正确的子类。我尝试在 BaseGenerator 的 new 方法中实现这个逻辑,但这会导致递归问题 现在我这样调用生成器:

generator = BaseGenerator(...)

问题是,当 BaseGenerator 重定向到子类时,它会以某种方式导致递归问题。如何修改此方法以从 BaseGenerator 动态实例化正确的子类而不导致递归?

任何有关如何正确实施此模式的建议或见解将不胜感激。

python-3.x django recursion design-patterns
1个回答
0
投票

在您编写的代码中,您只需从其自己的

__new__
方法实例化一个类(即使子类有自己的
__new__
,它们最终也必须调用
super().__new__
,您就会陷入再次递归。

您需要做的是,知道实际创建实例的是

object.__new__
(在基类中称为
super().__new__
),将最终类传递给 that 调用:

在此设计中需要考虑的另一件事是,如果

__init__
返回其自己类的实例,Python 仅在实例中调用
__new__
- 如果它返回任何其他内容,包括其中
 的类的子类__new__
是,
__init__
必须手动调用。

因此,进一步简化您的代码片段,这就是想法:

class Base:
    def __new__(cls):
        final_cls = SubClass1 # omitting _determine_subclass stub
        instance = super().__new__(final_cls)
        instance.__init__()
        return instance
        
    def __init__(self):
        print("At Base init")


class SubClass1(Base):
    def __init__(self):
        print("At subclass init")
        super().__init__()

b = Base()

实际上,我自己不止一次地使用过这种模式 - 我最喜欢的用途是这些类,它们在解析表达式时充当标记,并在解析后充当 AST 节点:

https://github.com/turicas/rows/blob/c0b24ce41e2ef08324bd3ee04ffc9800b6f950f3/rows/utils/query.py#L55

    ...

    def __new__(cls, value=_sentinel):
        """Specialized __new__ acts as a factory for whatever subclass best matches
        what is given as "value". Inheritance of subclasses, though, work as usual:
        it is just class instantiation for all subclasses that is centralized here.

        (I wonder if there is a "gang of four name" for this)
        """
        ...
© www.soinside.com 2019 - 2024. All rights reserved.