Python 在子类列表之前应该考虑什么?

Python 在子类列表之前应该考虑什么?,python,list,subclassing,Python,List,Subclassing,我最近检查了我遇到的一个编码问题,有人在查看代码时说子类列表很糟糕(我的问题与该类无关)。他说你不应该这样做,而且会带来一系列不良副作用。这是真的吗 我想问的是,如果列表对子类来说通常是不好的,那么原因是什么。另外,在Python中的子类列表之前我应该考虑什么? < P>我想我问自己的第一个问题是:“我的新对象真的是一个列表吗?”它走路像一张单子,说话像一张单子吗?还是别的什么 如果它是一个列表,那么所有的标准列表方法都应该有意义 如果标准列表方法没有意义,那么对象应该包含列表,而不是列表 在旧

我最近检查了我遇到的一个编码问题,有人在查看代码时说子类列表很糟糕(我的问题与该类无关)。他说你不应该这样做,而且会带来一系列不良副作用。这是真的吗


我想问的是,如果列表对子类来说通常是不好的,那么原因是什么。另外,在Python中的子类列表之前我应该考虑什么?

< P>我想我问自己的第一个问题是:“我的新对象真的是一个列表吗?”它走路像一张单子,说话像一张单子吗?还是别的什么

如果它是一个列表,那么所有的标准列表方法都应该有意义

如果标准列表方法没有意义,那么对象应该包含列表,而不是列表

在旧python(2.2?)中,由于各种技术原因,子分类列表是一个坏主意,但在现代python中它是好的。

Nick是正确的。 另外,虽然我不会讲Python,但在其他OO语言(Java、Smalltalk)中,将列表子类化是一个坏主意。通常应避免继承,而应使用委托组合

而是创建一个容器类并委托调用列表。容器类有一个对列表的引用,您甚至可以在自己的方法中公开列表的调用和返回。 这增加了灵活性,并允许您在以后更改实现(不同的列表类型或数据结构),而不破坏任何代码。如果希望列表执行不同的列表类型的操作,那么容器可以执行此操作,并将普通列表用作简单的数据结构。 想象一下,如果列表有47种不同的用法。你真的想维护47个不同的子类吗? 相反,您可以通过容器和接口来实现这一点。一个类,用于维护并允许人们通过接口调用新的和改进的方法,实现保持隐藏状态。

模块中提供的,尤其是
MutableSequence
,在实现类似列表的类时非常有用。这些在Python2.6及更高版本中可用

使用ABCs,您可以实现类的“核心”功能,它将提供逻辑上依赖于您定义的方法

例如,在
集合.Sequence
派生类中实现
\uuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu


您可能仍然希望使用包含的列表对象来完成繁重的工作。

子类化
list
没有任何方法会使用您重写的任何方法,因此可能会出现意外的错误。此外,做
self.append
而不是
self.foos.append
或者特别是
self[4]
而不是
self.foos[4]
来访问您的数据常常会让人困惑。你可以做一些像列表一样工作的东西,或者(更好)像你真正想要的列表,而只是子类化
对象

+1只有当它真正有100%的意义时才继承,否则就合成。至于副作用,他有点过时了?数据包含在一个列表中,但为了完成许多事情,我需要在列表顶部添加许多其他特定方法。是的,为“is-a”关系继承,为几乎所有其他关系组合。子类化列表本身并不坏,但在许多情况下,它确实不是您想要做的。除非您提供详细信息,否则我们无法回答此处是否存在这种情况。如果我们要向列表中添加属性,该怎么办?例如,假设我们有mylist=[]。我们需要类似mylist.x=3的东西。@Selinap,如果我希望我的状态包含一个某物列表和一个int,我仍然可能使用composition。使用继承来实现这一点会在编写和使用中造成混乱,并不会真正为您带来任何好处。这似乎与Python3不符。这些文件明确包含了用于此目的的内容。它甚至暗示从列表中进行子类化现在是可能的:“这个类的需求已经被直接从列表中进行子类化的能力部分取代了;”(我知道这是一个老话题,上面的评论在写的时候可能是真的,只是想让现在发现这个问题的人明白这点)@Claude,有人喜欢这样一个抽象事实,即自从引入了新样式的类之后,可以对内置函数进行子类化(没有抛出错误),但事实是它实际上是无用的。子类化列表有大量未定义的行为,而真正的行为是无用的“没有什么是虚拟的”。在Python2或Python3中,子类
collections.MutableSequence
object
(2)/nothing(3)更有用。自Python3.3+以来,它已被移动到模块中。