【问题标题】:How to initiallize subclass from superclass method?如何从超类方法初始化子类?
【发布时间】:2020-02-05 04:32:29
【问题描述】:

我在网上看到重载构造函数的pythonic方法是创建类方法。所以我创建了一个RectF 类,它可以通过两种方式之一进行初始化。

class RectF:
    def __init__(self, x: float, y: float, w, h):
        self.x: float = x
        self.y: float = y
        self.width = w
        self.height = h

    @classmethod
    def from_tuples(cls, pos: tuple, size: tuple):
        return cls(pos[0], pos[1], size[0], size[1])

init 构造函数为每个字段接受一个参数,而from_tuples 方法接受两个分别包含坐标和大小的元组。

但是,当我去初始化一个子类的实例时,使用from_tuples 方法,会抛出一个异常。使用super().__init__() 工作正常。

class Entity(RectF):
    def __init__(self, pos: tuple, size: tuple, vel: tuple):
        super().__init__(pos[0], pos[1], size[0], size[1])

        # I would like to initialize the superclass using the from_tuples class method.
        # super().from_tuples(pos, size)
        # This throws the following exception: __init__() takes 4 positional arguments but 5 were given

        self.vel_x = vel[0]
        self.vel_y = vel[1]

上面的代码是一个示例,现在可以正常工作。但是为了可读性和可维护性;作为最佳实践,使用最少的参数初始化对象会很有用,尤其是当它们随着时间的推移变得更加复杂时。

【问题讨论】:

    标签: python inheritance methods initialization superclass


    【解决方案1】:

    __init__被调用时,对象已经被构造好了,所以使用from_tuples已经太迟了。

    不要使用参数的数量来衡量简单性。相反,考虑哪些方法可用于实现其他方法。如果您希望元组成为矩形的基本构建块,您可以这样做:

    class RectF:
        def __init__(self, pos: tuple, size: tuple):
            self.x: float = pos[0]
            self.y: float = pos[1]
            self.width = size[0]
            self.height = size[1]
    
        # No good name for this method comes to mind
        @classmethod
        def from_separate_values(cls, x, y, w, h):
            return cls((x, y), (w, h))
    
    
    class Entity(RectF):
        def __init__(self, pos: tuple, size: tuple, vel: tuple):
            super().__init__(pos, size)
            self.vel_x = vel[0]
            self.vel_y = vel[1]
    
        @classmethod
        def from_separate_values(cls, x, y, w, h, vx, vy):
            rv = super().from_separate_values(x, y, w, h)
            rv.vel_x = vx
            rv.vel_y = vy
            return rv
    

    【讨论】:

    • vel 参数应该是可选的,这样Entity.from_separate_values 才能工作。
    • 鉴于vel 似乎是Entity 的定义特征,我认为覆盖from_separate_values 更有意义。
    • 是的,有道理。
    猜你喜欢
    • 1970-01-01
    • 2016-06-13
    • 1970-01-01
    • 2017-01-12
    • 2011-04-11
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多