我最近正在处理我遇到的一个编码问题,有人查看代码说子类列表很糟糕(我的问题与那个类无关)。他说你不应该这样做,而且它带来了一堆不好的副作用。这是真的?
我在问 list 通常对子类是否不好,如果是,原因是什么。或者,在 Python 中对列表进行子类化之前我应该考虑什么?
我最近正在处理我遇到的一个编码问题,有人查看代码说子类列表很糟糕(我的问题与那个类无关)。他说你不应该这样做,而且它带来了一堆不好的副作用。这是真的?
我在问 list 通常对子类是否不好,如果是,原因是什么。或者,在 Python 中对列表进行子类化之前我应该考虑什么?
模块中提供的抽象基类collections
,尤其MutableSequence
是在实现类似列表的类时非常有用。这些在 Python 2.6 及更高版本中可用。
使用 ABC,您可以实现类的“核心”功能,它将提供逻辑上取决于您定义的方法。
例如,__getitem__
在collections.Sequence
派生类中实现就足以为您的类提供__contains__
、__iter__
和其他方法。
您可能仍希望使用包含的列表对象来完成繁重的工作。
子类化没有任何好处list
。这些方法都不会使用您覆盖的任何方法,因此您可能会遇到意外错误。此外,做一些事情self.append
而不是self.foos.append
或特别是self[4]
而不是self.foos[4]
访问您的数据经常会让人感到困惑。您可以制作与列表完全相同的东西,或者(更好)像您真正想要的列表一样,而只是子类化object
。
我想我要问自己的第一个问题是,“我的新对象真的是一个列表吗?”。它像列表一样走路,像列表一样说话吗?或者是别的什么?
如果它是一个列表,那么所有标准的列表方法都应该是有意义的。
如果标准列表方法没有意义,那么您的对象应该包含一个列表,而不是一个列表。
在旧的 python (2.2?) 中,由于各种技术原因,子类列表是一个坏主意,但在现代 python 中它很好。
尼克是正确的。此外,虽然我不会说 Python,但在其他 OO 语言(Java、Smalltalk)中,将列表子类化是一个坏主意。一般应避免继承,而应使用委托组合。
相反,您创建一个容器类并将调用委托给列表。容器类具有对列表的引用,您甚至可以在自己的方法中公开列表的调用和返回。这增加了灵活性,并允许您稍后更改实现(不同的列表类型或数据结构)而不破坏任何代码。如果您希望您的列表执行不同的列表类型的事情,那么您的容器可以执行此操作并将普通列表用作简单的数据结构。想象一下,如果您有 47 种不同的列表用途。你真的要维护 47 个不同的子类吗?相反,您可以通过容器和接口来做到这一点。一个类来维护并允许人们通过接口调用您的新方法和改进方法,而实现保持隐藏。