Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing a list in Python. Why does slice and empty list not work?

I am befuddled over what I think is a very simple and straight forward subclass of a list in Python.

Suppose I want all the functionality of list. I want to add several methods to the default set of a list.

The following is an example:

class Mylist(list):

    def cm1(self):
        self[0]=10

    def cm2(self):
        for i,v in enumerate(self):
            self[i]=self[i]+10        

    def cm3(self):
        self=[]         

    def cm4(self):
        self=self[::-1]

    def cm5(self):
        self=[1,2,3,4,5]       

ml=Mylist([1,2,3,4])
ml.append(5)
print "ml, an instance of Mylist: ",ml
ml.cm1()
print "cm1() works: ",ml

ml.cm2()
print "cm2() works: ",ml

ml.cm3() 
print "cm3() does NOT work as expected: ",ml     

ml.cm4()
print "cm4() does NOT work as expected: ",ml     

ml.cm5()
print "cm5() does NOT work as expected: ",ml  

The output:

Mylist:  [1, 2, 3, 4, 5]
cm1() works:  [10, 2, 3, 4, 5]
cm2() works:  [20, 12, 13, 14, 15]
cm3() does NOT work as expected:  [20, 12, 13, 14, 15]
cm4() does NOT work as expected:  [20, 12, 13, 14, 15]
cm5() does NOT work as expected:  [20, 12, 13, 14, 15]

So it seems that a scalar assignment works as I expect and understand. List or slices do not work as I understand. By 'does not work,' I mean that the code in the method does not change the instance of ml as the first two methods do.

What do I need to do so that cm3() cm4() and cm5() work?

like image 645
dawg Avatar asked Dec 17 '22 03:12

dawg


2 Answers

The problem here is that in cm3, cm4, and cm5, you are not modifying the object! You are creating a new one in the scope of the member function, and then assigning it to self. The outer scope doesn't respect this. In cm1 and cm2, you are modifying the same object, so the object stays the same.

Try using the id function to debug this:

def cm4(self):
    self=self[::-1]
    print 'DEBUG', id(self)

...

m1.cm4()
print 'DEBUG', id(self)

You'll see that the id is different.

So, you might ask, well how do I do this? You are lucky that with lists you can assign into a splice. This might not be as easy with other data structures. What this does is keeps the same list, but replaces the items. To do this, do:

self[:] = ...

So, for example:

self[:] = self[::-1]
like image 136
Donald Miner Avatar answered May 11 '23 00:05

Donald Miner


Your misunderstanding is that there is something special about the word self. In those methods it is just a name in scope like any other name in python, so when you reassign it, you are just rebinding the name self to some other object - not mutating the parent object. In fact that argument doesn't even need to be named self, that is only a convention that python programmers use.

Here is reimplementation of your members to mutate properly:

def cm3(self):
  self[:] = []

def cm4(self):
  self.reverse()

def cm5(self):
  self[:] = [1,2,3,4,5]
like image 36
wim Avatar answered May 11 '23 01:05

wim