我需要一个容器,它可以收集许多对象,并提供一些关于容器元素的报告功能。基本上,我希望能够做到:

magiclistobject = MagicList()
magiclistobject.report()  ### generates all my needed info about the list content

所以我考虑对普通列表进行子类化,并添加一个report()方法。这样,我就可以使用所有内置的列表功能。
class SubClassedList(list):
    def __init__(self):
        list.__init__(self)


    def report(self):      # forgive the silly example
        if 999 in self:
            print "999 Alert!"

相反,我也可以创建自己的类,该类具有magicList属性,但如果我想使用以下方法访问列表,则必须创建用于追加、扩展等的新方法:
magiclistobject.append() # instead of magiclistobject.list.append()

我需要这样的东西(这似乎是多余的):
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!"

我认为将列表分为子类是一件轻而易举的事情。但这听起来像是一个“不”字。为什么?

最佳答案

扩展列表可能不好的一个原因是,它将“magicReport”对象与列表联系得太紧密。例如,python列表支持以下方法:

append
count
extend
index
insert
pop
remove
reverse
sort

它还包含一整套其他操作(添加、使用<>进行比较、切片等)。
您的“magicReport”对象是否真正想要支持所有这些操作?例如,以下是合法的python:
b = [1, 2]
b *= 3
print b   # [1, 2, 1, 2, 1, 2]

这是一个很做作的例子,但是如果您从“list”继承,那么如果有人无意中做了类似的事情,您的“magicReport”对象将执行完全相同的操作。
作为另一个例子,如果你尝试切片你的magicReport对象呢?
m = MagicReport()

# Add stuff to m

slice = m[2:3]
print type(slice)

您可能会期望切片是另一个magicReport对象,但它实际上是一个列表。您需要覆盖__getslice__以避免意外行为,这有点痛苦。
它还使您更难更改magicReport对象的实现。如果您最终需要进行更复杂的分析,那么将底层数据结构更改为更适合该问题的结构通常会有所帮助。
如果您对列表进行子类化,您可以通过提供新的appendextend等方法来解决这个问题,这样您就不会更改接口,但除非您通读整个代码库,否则您将没有任何明确的方法来确定实际使用的列表方法。但是,如果您使用组合,只需要一个列表作为字段,并为您支持的操作创建方法,那么您就完全知道需要更改什么。
实际上,我最近遇到了一个和你工作时非常相似的情况。我有一个对象,其中包含一个“things”集合,我首先在内部将其表示为一个列表。随着项目需求的变化,我最终将对象更改为在内部使用dict(自定义集合对象),然后快速地连续使用ordereddict。至少在我的经验中,组合使更改某个东西的实现方式比继承更容易。
尽管如此,我认为在“magicReport”对象合法地是除名称之外的所有列表的情况下,扩展列表可能是可以的。如果你真的想用magicReport作为一个列表的每一种方式,并且不打算改变它的实现,那么它可能只是更方便的子类列表和完成它。
不过,在这种情况下,最好只使用一个列表并编写一个“report”函数——我无法想象您需要多次报告列表的内容,并为此目的使用自定义方法创建一个自定义对象可能会被过度破坏(尽管这显然取决于正是你想做的)

07-24 09:38
查看更多