在Python中对列表进行子类化。为什么切片和空列表不起作用?

时间:2012-02-27 03:22:12

标签: python list subclass

我对我认为是Python中列表的一个非常简单和直接的子类感到困惑。

假设我想要列表的所有功能。我想将几个方法添加到列表的默认集中。

以下是一个例子:

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  

输出:

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]

因此,似乎标量赋值的工作方式与我期望和理解的一样。列表或切片不能像我理解的那样工作。通过“不起作用”,我的意思是方法中的代码不会像前两个方法那样改变ml的实例。

我需要做什么才能使cm3() cm4()cm5()有效?

3 个答案:

答案 0 :(得分:6)

问题在于cm3cm4cm5,您不是在修改对象!您正在成员函数的范围内创建一个新的,然后将其分配给self。外部范围不尊重这一点。在cm1cm2中,您正在修改同一个对象,因此该对象保持不变。

尝试使用id函数进行调试:

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

...

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

您会看到id不同。

所以,你可能会问,我该怎么做?您很幸运,您可以将列表分配到拼接中。对于其他数据结构,这可能不那么容易。这样做是保持相同的列表,但替换项目。为此,请执行以下操作:

self[:] = ...

所以,例如:

self[:] = self[::-1]

答案 1 :(得分:4)

你的误解是self这个词有一些特别之处。在这些方法中,它只是范围中的名称,就像python中的任何其他名称一样,因此当您重新分配它时,您只需将名称self重新绑定到其他对象 - 而不是改变父对象。实际上,该参数甚至不需要命名为self,这只是python程序员使用的约定。

以下是您的成员重新实现以正确变异:

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

def cm4(self):
  self.reverse()

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

答案 2 :(得分:2)

使用self[:]代替self,self = ...会将自变量重新绑定到其他对象,这不会更改列表对象。

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

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

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