为了账号安全,请及时绑定邮箱和手机立即绑定

强制使用专门的子类

强制使用专门的子类

qq_笑_17 2021-09-24 15:20:54
当使用某些参数调用超类时,我试图强制使用更专业的类。具体来说,我有一个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 = coefclass 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__方法(带有不匹配的签名)。这样做的最佳方法是什么?
查看完整描述

2 回答

?
杨魅力

TA贡献1811条经验 获得超6个赞

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


查看完整回答
反对 回复 2021-09-24
?
aluckdog

TA贡献1847条经验 获得超7个赞

调用类时返回不同类类型的__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)

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”使用的其他机制。


查看完整回答
反对 回复 2021-09-24
  • 2 回答
  • 0 关注
  • 196 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号