Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
238 views
in Technique[技术] by (71.8m points)

python - Should I subclass list or create class with list as attribute?

I need a container that can collect a number of objects and provides some reporting functionality on the container's elements. Essentially, I'd like to be able to do:

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

So I thought of subclassing the normal list and adding a report() method. That way, I get to use all the built-in list functionality.

class SubClassedList(list):
    def __init__(self):
        list.__init__(self)
    
    
    def report(self):      # forgive the silly example
        if 999 in self:
            print "999 Alert!"
        

Instead, I could also create my own class that has a magiclist attribute but I would then have to create new methods for appending, extending, etc., if I want to get to the list using:

magiclistobject.append() # instead of magiclistobject.list.append()

I would need something like this (which seems redundant):

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!"

I thought that subclassing the list would be a no-brainer. But this post here makes it sounds like a no-no. Why?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

One reason why extending list might be bad is since it ties together your 'MagicReport' object too closely to the list. For example, a Python list supports the following methods:

append
count
extend
index
insert
pop
remove
reverse
sort

It also contains a whole host of other operations (adding, comparisons using < and >, slicing, etc).

Are all of those operations things that your 'MagicReport' object actually wants to support? For example, the following is legal Python:

b = [1, 2]
b *= 3
print b   # [1, 2, 1, 2, 1, 2]

This is a pretty contrived example, but if you inherit from 'list', your 'MagicReport' object will do exactly the same thing if somebody inadvertently does something like this.

As another example, what if you try slicing your MagicReport object?

m = MagicReport()

# Add stuff to m

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

You'd probably expect the slice to be another MagicReport object, but it's actually a list. You'd need to override __getslice__ in order to avoid surprising behavior, which is a bit of a pain.


It also makes it harder for you to change the implementation of your MagicReport object. If you end up needing to do more sophisticated analysis, it often helps to be able to change the underlying data structure into something more suited for the problem.

If you subclass list, you could get around this problem by just providing new append, extend, etc methods so that you don't change the interface, but you won't have any clear way of determining which of the list methods are actually being used unless you read through the entire codebase. However, if you use composition and just have a list as a field and create methods for the operations you support, you know exactly what needs to be changed.

I actually ran into a scenario very similar to your at work recently. I had an object which contained a collection of 'things' which I first internally represented as a list. As the requirements of the project changed, I ended up changing the object to internally use a dict, a custom collections object, then finally an OrderedDict in rapid succession. At least in my experience, composition makes it much easier to change how something is implemented as opposed to inheritance.


That being said, I think extending list might be ok in scenarios where your 'MagicReport' object is legitimately a list in all but name. If you do want to use MagicReport as a list in every single way, and don't plan on changing its implementation, then it just might be more convenient to subclass list and just be done with it.

Though in that case, it might be better to just use a list and write a 'report' function -- I can't imagine you needing to report the contents of the list more than once, and creating a custom object with a custom method just for that purpose might be overkill (though this obviously depends on what exactly you're trying to do)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...