Arn*_*rne 8 python list subclass extend
我需要一个可以收集大量对象的容器,并在容器的元素上提供一些报告功能.基本上,我希望能够做到:
magiclistobject = MagicList()
magiclistobject.report() ### generates all my needed info about the list content
Run Code Online (Sandbox Code Playgroud)
所以我想到了对普通列表进行子类化并添加了一个report()方法.这样,我就可以使用所有内置列表功能.
class SubClassedList(list):
def __init__(self):
list.__init__(self)
def report(self): # forgive the silly example
if 999 in self:
print "999 Alert!"
Run Code Online (Sandbox Code Playgroud)
相反,我也可以创建我自己的具有magiclist属性的类,但是如果我想使用以下命令到达列表,我将不得不创建新的方法来追加,扩展等.
magiclistobject.append() # instead of magiclistobject.list.append()
Run Code Online (Sandbox Code Playgroud)
我需要这样的东西(这似乎是多余的):
class MagicList():
def __init__(self):
self.list = []
def append(self,element):
self.list.append(element)
def extend(self,element):
self.list.extend(element)
# more list functionality as needed...
def report(self):
if 999 in self.list:
print "999 Alert!"
Run Code Online (Sandbox Code Playgroud)
我认为对列表进行子类化将是一个明智的选择.但这篇文章让这听起来像是禁忌.为什么?
Mic*_*x2a 11
扩展列表可能不好的一个原因是因为它将"MagicReport"对象与列表过于紧密地联系在一起.例如,Python列表支持以下方法:
append
count
extend
index
insert
pop
remove
reverse
sort
Run Code Online (Sandbox Code Playgroud)
它还包含许多其他操作(添加,比较使用<和>切片等).
所有这些操作都是你的'MagicReport'对象真正想要支持的吗?例如,以下是合法的Python:
b = [1, 2]
b *= 3
print b # [1, 2, 1, 2, 1, 2]
Run Code Online (Sandbox Code Playgroud)
这是一个非常人为的例子,但是如果你从'list'继承,你的'MagicReport'对象会做同样的事情,如果有人无意中做了这样的事情.
另外一个例子,如果你尝试切割MagicReport对象怎么办?
m = MagicReport()
# Add stuff to m
slice = m[2:3]
print type(slice)
Run Code Online (Sandbox Code Playgroud)
您可能希望切片是另一个MagicReport对象,但它实际上是一个列表.你需要覆盖__getslice__以避免令人惊讶的行为,这有点痛苦.
它还使您更难以更改MagicReport对象的实现.如果您最终需要进行更复杂的分析,那么通常可以将基础数据结构更改为更适合问题的结构.
如果你是list的子类,你可以通过提供new append,extend等方法来解决这个问题,这样就不会改变接口,但是你不会有任何明确的方法来确定实际使用哪个列表方法,除非你仔细阅读整个代码库.但是,如果您使用合成并且只将列表作为字段并为您支持的操作创建方法,则您确切知道需要更改的内容.
我实际上遇到了一个与你最近的工作非常相似的场景.我有一个对象,其中包含我首先在内部表示为列表的"事物"集合.随着项目要求的改变,我最终将对象更改为内部使用dict,自定义集合对象,最后是快速连续的OrderedDict.至少根据我的经验,组合使得更改某些内容的实现变得更容易,而不是继承.
话虽这么说,我认为扩展列表可能适用于你的'MagicReport'对象合法地除了名称之外的所有列表的情况.如果您确实希望将MagicReport作为列表以单一方式使用,并且不打算更改其实现,那么它可能更方便子类列表并且只是完成它.
虽然在这种情况下,最好只使用一个列表并编写一个"报告"函数 - 我无法想象您需要多次报告列表的内容,并使用自定义方法创建自定义对象只是为了这个目的可能是矫枉过正(虽然这显然取决于你究竟想要做什么)
通常,只要您问自己“我应该继承还是拥有该类型的成员”,请选择不继承。这种经验法则被称为“偏重继承而不是继承”。
之所以如此,是因为:组合适合您要使用其他类的功能的情况;如果其他代码需要将其他类的功能与正在创建的类一起使用,则继承是适当的。