当使用某些参数调用超类时,我试图强制使用更专门的类。具体来说,我有一个Monomial
类(其__init__
接受coef
不足和power
)和一个Constant
类。我希望每当Monomial
被power=0
调用时,都返回一个Constant
实例。
这些类的目的是建立一个用于生成“随机”数学函数的框架。
我最初的经历:
class Monomial(Function):
def __init__(self, coef: int, power: int, inner=Identity()):
super().__init__(inner)
self.pow = power
self.coef = coef
class Constant(Monomial):
def __init__(self, c: int):
super().__init__(c, 0)
我尝试添加以下__new__
方法:
class Monomial(Function):
def __new__(cls, coef: int, power: int, inner=Identity()):
if power == 0:
return Constant(coef)
instance = object.__new__(Monomial)
instance.__init__(coef, power, inner)
return instance
问题在于,现在每当创建新的Constant
时,就会调用Monomial
的{{1}}方法(签名不匹配)。
执行此操作的最佳方法是什么?
答案 0 :(得分:3)
使用factory method
方法怎么样?当确切的实例类型应动态定义时,这是一个不错的选择。看起来像:
class Monomial(Function):
@staticmethod
def create(coef: int, power: int, inner=Identity()):
if power == 0:
return Constant(coef)
else:
return Monomial(coef, power)
x = Monomial.create(...)
答案 1 :(得分:1)
调用类时返回不同类类型的方法是重写__new__
方法,而不是__init__
。 __new__
返回的值是用作实例的值(与__init__
不同,它甚至不允许返回值)。您已正确启动,但尝试在__new__
内部通过调用实例化子类,只会重新输入Monomial.__new__
-您可能会在此处遇到递归错误。
因此,即使Python允许更改__new__
的返回类型,也许您也应该考虑拥有一个工厂函数(独立于任何类)的想法,该函数将返回适当类的实例。有时“越简单越好”。
无论如何,工厂方法的代码是:
class Monomial(Function):
def __init__(self, coef: int, power: int, inner=Identity()):
super().__init__(inner)
self.pow = power
self.coef = coef
class Constant(Monomial):
def __init__(self, c: int):
super().__init__(self, coef=c, power=0)
...
def create_monomial(coef, power):
if power == 0:
return Constant(coef)
return Monomial(coef, power)
(您可能会发现create_monomial也可以是静态或类方法)
而且,如果您真的认为这样会更好,则解开__new__
方法的一种方法是:
class Monomial(Function):
def __new__(cls, coef: int, power: int = 0, inner=Identity()):
if power == 0:
cls = Constant
return super().__new__(cls)
class Constant(Monomial):
def __init__(self, c: int, **kw):
super().__init__(c, 0)
如果__init__
的返回是__new__
的实例,Python的实例化机制将调用self
-因此将正确调用Monomial和常量__init__
。您只需要修复Constant的__init__
就不会破坏它会得到的power = 0
的局部参数。
在这里修复签名将花费更多的工作,并且可能涉及使用元类来实际上吞并其常量__call__
中未使用的power
到Constant的__init__
;
还请注意,这里的“真正的解决方法”是调用super().__new__
需要显式传递该类-与super()
的其他用法不同,其中{self}或“ cls”由Python提供。这是由于__new__
实际上是一个静态方法-Python在构建类时向其中添加了cls
,但是通过“ classmethods”所使用的其他机制。