在Python中子类化一个列表

3

我正在跟随一个在线教程,代码如下:

class Hands(list):
    def __init__(self, size=0, die_class=None, *args, **kwargs):
        if not die_class:
            raise ValueError("You must provide a die class")
        super().__init__()

        for _ in range(size):
            self.append(die_class())

这基本上是用一些骰子(size)和它们所持有的骰子(die_class)来模拟玩家。

我困惑的是为什么我们需要调用super().__init__?我尝试了没有它的代码,而且它也可以正常运行!为什么这个调用是必要的呢?


1
即使现在它能够正常工作,因为list似乎不需要默认构造函数,但是如果下一个Python版本要求调用list对象的__init__呢?为什么不调用__init__呢? - Jean-François Fabre
这并非必须(但是这是一个好的实践),请参考https://softwareengineering.stackexchange.com/questions/318165/is-calling-the-superclass-constructor-in-a-subclass-really-important - Paco H.
我认为它违反了Liskov原则。虽然目前能够正常工作,但它什么时候会出问题呢? - Jean-François Fabre
1
可能是Subclassing dict: should dict.__init__() be called?的重复问题。 - quamrana
2个回答

2
你需要调用基类的__init__()来确保其中的任何初始化代码都会运行。如果没有进行这个调用,看起来似乎也能工作,但这可能只是巧合,或者你还没有遇到由此导致的问题。即使在当前使用的Python版本和实现中它能够一致地工作,也不能保证其他版本和实现在不调用基类的__init__方法时能够正常工作。
此外,你可以实际上使用这个调用来用你的骰子对象填充列表:
class Hands(list):
    def __init__(self, size=0, die_factory=None):
        if not die_factory:
            raise ValueError('You must provide a die factory')
        super().__init__(die_factory() for _ in range(size))

我已经将die_class重命名为die_factory,因为任何可调用的函数都可以在此处生成新的骰子对象。
注意:除非一个Hands对象实际上是一个list,即列表的所有方法和行为也适用于Hands对象,否则您可能会违反is-a关系。

-1

super()让你避免显式地引用基类。更重要的是,在多重继承中,你可以做像this这样的事情。归根结底,这并不是必需的,只是一个好的实践。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接