【问题标题】:Create subclass from superclass initializer in Python在 Python 中从超类初始化器创建子类
【发布时间】:2022-01-23 00:48:52
【问题描述】:

假设我有一个类 Fruit 和它的两个子类 Orange(Fruit)Banana(fruit)

Fruit 有一个初始化器,我向它传递了一些参数。但我不希望它仅仅创建并返回一个 fruit,而是根据传递给它的参数,可能返回它的几个不同 子类 之一。例如:

Fruit(color="yellow") 可能返回 Banana 对象,而 Fruit(color="orange") 将返回 Orange

我该怎么做?我不能在__init__ 中这样做,因为已经创建了该类。我尝试在__new__ 中执行此操作,但结果很混乱,因为我可以创建子类(如预期的那样),但随后会递归调用超类的__new__

我的解决方法是只定义一个 Fruit.create() 静态方法来创建适当的子类,但这似乎有点不符合 Python 风格。

有没有“正确”的方法来做到这一点?

【问题讨论】:

  • 这似乎有点倒退,Fruit 是一个类,所以你为什么期望它在初始化时返回一个不同的类。这似乎比创建一个为您提供正确水果类的静态方法更不合常理
  • @ChrisDoyle 如果你告诉别人给你一个水果,他们给了你一个香蕉,他们会错吗? ;-)
  • 我不反对向水果索取的工厂方法。对我来说似乎是 var = foo() 的想法,其中 foo 是一个类,但最终从它的 init 返回的不是foo 的实例,而是bar 的实例。但是在fruit中调用工厂方法来获取子类是有意义的

标签: python python-3.x


【解决方案1】:

我的观点和 Chris Doyle 一样。

你可以使用工厂模式或者你的Fruit.create(),我觉得他们很好

如果你想使用你的想法,你可以这样做


class Meta(type):
    def __call__(cls, *args, **kwargs):
        if cls is Fruit:
            color = kwargs.pop('color', None)
            if color is None:
                raise ValueError("missing keyword argument `color`")
            match color:
                case 'yellow':
                    return Banana()
                case 'orange':
                    return Orange()
                case _:
                    raise ValueError("invalid color: %s" % color)

        return super().__call__(*args, **kwargs)


class Fruit(metaclass=Meta):
    def __init__(self, *, color=None):  # noqa
        pass


class Banana(Fruit):
    pass


class Orange(Fruit):
    pass


if __name__ == '__main__':
    print(Fruit(color='yellow'))
    print(Fruit(color='orange'))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2020-02-05
    • 2017-01-09
    • 1970-01-01
    相关资源
    最近更新 更多