猿问

强制使用专门的子类

当使用某些参数调用超类时,我试图强制使用更专业的类。具体来说,我有一个Monomial类(它__init__需要coefficient 和power)和一个Constant类。我希望每当Monomial调用 with 时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创建一个 new 时,都会调用Monomial's__new__方法(带有不匹配的签名)。


这样做的最佳方法是什么?


qq_笑_17
浏览 197回答 2
2回答

杨魅力

使用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(...)

aluckdog

调用类时返回不同类类型的__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 = coefclass 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)Python 的实例化机制将调用__init__如果返回__new__的实例是self- 因此 Monomial 和 Constant__init__都将被正确调用。你只需要修复 Constant's__init__不要破坏power = 0它会得到的 ocasional参数。修复签名将在那里花费更多的工作,并且可能涉及使用元类来实际吞咽,在其__call__方法中未使用powerConstant 的__init__;另请注意,此处的“真正修复”是调用super().__new__需要显式传递类 - 与super()Python 提供的“self”或“cls”的其他用法不同。这是因为__new__它实际上是一个静态方法——Pythoncls在构建类时向其中添加了,但是通过“classmethods”使用的其他机制。
随时随地看视频慕课网APP

相关分类

Python
我要回答