我正在重构一个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 动态实例化正确的子类而不导致递归?
任何有关如何正确实施此模式的建议或见解将不胜感激。
在您编写的代码中,您只需从其自己的
__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 节点:
...
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)
"""
...