【问题标题】:Automatic Initialization of subclass in superclass超类中子类的自动初始化
【发布时间】:2020-06-17 19:38:56
【问题描述】:

Initialize subclass within class in python 中提出了类似的问题。那里的答案得出的结论是应该避免这种方法,我不确定这是否适用于以下情况,我想知道如何实现它,或者我应该怎么做。

class Rational():
    def __init__(self, numerator, denominator):
        self.numerator = numerator
        self.denominator = denominator
        if self.denominator == 1:
            pass
            # >>> How to initialize as Integer in this case? <<<

    # ... More methods for rationals


class Integer(Rational):
    def __init__(self, value):
        super().__init__(value, 1)
        self.value = value

    # ... More methods for integers

在这个文件中,我有简单的整数类和Rational 数字类。由于所有Integers 都是有理数,Integer 是有理数的子类,我们调用super() 以允许整数调用有理数的方法。

不过,如果 Rational 用分母 1 初始化时,它可以被自动识别为整数,那就太好了。例如,我希望 x = Rational(4, 1) 然后允许我调用 x.integer_method() 甚至让 Integer(4) == x 返回 True。问题是,我不知道我是否可以从 Rational 初始化程序中调用 Integer 初始化程序,因为我可能会陷入无限循环。

解决这个问题的最佳方法是什么(通常不仅适用于整数和有理数,而且适用于任何父子类型,其中 Parent 的实例在语义上可能不被识别为 Child 类型的成员直到初始化时间?

【问题讨论】:

  • 听起来像教科书用例,用于替换构造函数的工厂方法。
  • 如果为Rational类定义了一个__new__()方法,当条件满足时,它可以返回一个Integer的实例。例如,请参阅我对问题 Improper use of _new_ to generate classes? 的回答。
  • 糟糕的设计模式,不是很稳固
  • @Pynchia:不是最好的评论,因为它假设每个人都知道SOLID 的含义。

标签: python class inheritance


【解决方案1】:

使用__new__ 定义类的构造方式,包括构造其他类。避免定义__init__,因为它不会在__new__ 返回另一个类型的对象时自动调用。由于该方案将类强耦合在一起,Integer 可以避免调用 super().__new__ 为简单起见。

class Rational():
    def __new__(cls, numerator, denominator=1):
        if denominator == 1:
            return Integer(numerator)
        self = object.__new__(cls)
        self.numerator = numerator
        self.denominator = denominator
        return self   # new always returns an instance

    def __repr__(self):
        return f'Rational({self.numerator}/{self.denominator})'

class Integer(Rational):
    denominator = 1  # as a Rational, Integer must expose numerator and denominator
    def __new__(cls, value):
        self = object.__new__(cls)
        self.numerator = value
        return self

    def __repr__(self):
        return f'Integer({self.numerator})'

这足以动态构造适当的子类:

>>> Rational(12, 3)
Rational(12/3)
>>> Rational(15, 1)
Integer(15)

理想情况下,此类类应该是不可变的;否则,IntegerRational 意味着 some_integer.denominator = 3 是有效的,并产生一个具有 1/3 初始值的 Rational

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-30
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 2016-06-13
    相关资源
    最近更新 更多