我对我认为是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()
有效?
答案 0 :(得分:6)
问题在于cm3
,cm4
和cm5
,您不是在修改对象!您正在成员函数的范围内创建一个新的,然后将其分配给self。外部范围不尊重这一点。在cm1
和cm2
中,您正在修改同一个对象,因此该对象保持不变。
尝试使用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]