我试图通过切片和for循环修改列表中的值,并遇到一些非常有趣的行为。如果有人可以解释这里内部发生的事情,我将不胜感激。
>>> x = [1,2,3,4,5]
>>> x[:2] = [6,7] #slices can be modified
>>> x
[6, 7, 3, 4, 5]
>>> x[:2][0] = 8 #indices of slices cannot be modified
>>> x
[6, 7, 3, 4, 5]
>>> x[:2][:1] = [8] #slices of slices cannot be modified
>>> x
[6, 7, 3, 4, 5]
>>> for z in x: #this version of a for-loop cannot modify lists
... z += 1
...
>>> x
[6, 7, 3, 4, 5]
>>> for i in range(len(x)): #this version of a for-loop can modify lists
... x[i] += 1
...
>>> x
[7, 8, 4, 5, 6]
>>> y = x[:2] #if I assign a slice to a var, it can be modified...
>>> y[0] = 1
>>> y
[1, 8]
>>> x #...but it has no impact on the original list
[7, 8, 4, 5, 6]
让我们按1分解您的评论1:
1.)x[:2] = [6, 7]
切片可以修改:
在这里查看这些答案。它__setitem__
从list
对象中调用方法并将其分配slice
给它。每次引用x[:2]
一个新的slice对象时,就可以创建一个对象(您可以简单地进行操作id(x[:2])
,很明显,它不会一次具有相同的ID)。
2.)切片的索引无法修改:
这不是真的。无法修改它,因为您是在slice
实例上执行分配,而不是在上执行分配list
,因此它不会触发在__setitem__
上执行list
。另外,int
它们是不可变的,因此无法以任何一种方式进行更改。
3.)切片的切片无法修改:
看上面。相同的原因-您要分配给切片的一个实例,而不是list
直接修改该实例。
4.)此版本的for循环无法修改列表:
z
这里引用的是元素中的实际对象x
。如果您使用id(z)运行for循环,则会注意到它们与相同id(6), id(7), id(3), id(4), id(5)
。即使list
包含所有5个相同的引用,在执行操作时,z = ...
您只会将新值分配给对象z
,而不是分配给存储在中的对象list
。如果您要修改list
,则需要按索引进行分配,出于同样的原因,您也无法预期1 = 6
会x
变成[6, 2, 3, 4, 5]
。
5.)此版本的for循环可以修改列表:
请参阅上面的答案。现在,您直接在list
而不是其代表上执行项目分配。
6.)如果我将切片分配给var,则可以对其进行修改:
如果您到目前为止一直在关注,您将意识到现在正在将的实例分配给x[:2]
对象y
,该对象现在是list
。故事如下-您通过上的索引执行项目分配y
,当然它将被更新。
7.)...但对原始清单没有影响:
当然。x
和y
是两个不同的对象。id(x) != id(y)
,因此对它执行的任何操作x
都不会影响y
。但是y = x
,如果您分配了,然后将更改为y
,则是的,x
也会受到影响。
为了进一步说明for z in x:
,假设您有一个,class foo()
并为列表分配了这样的两个实例f
:
f1 = foo()
f2 = foo()
f = [f1, f2]
f
# [<__main__.foo at 0x15f4b898>, <__main__.foo at 0x15f4d3c8>]
请注意,所涉及的引用是实际foo
实例,而不是对象f1
和f2
。因此,即使我执行以下操作:
f1 = 'hello'
f
# [<__main__.foo at 0x15f4b898>, <__main__.foo at 0x15f4d3c8>]
f
由于foo实例保持不变,即使对象f1
现在被分配了不同的值,它仍然保持不变。出于同样的原因,每当对z
in进行更改时for z in x:
,您只会影响该对象z
,但是列表中的任何内容都不会更改,直到您x
按索引更新为止。
但是,如果对象具有属性或是可变的,则可以在循环中直接更新引用的对象:
x = ['foo']
y = ['foo']
lst = [x,y]
lst
# [['foo'], ['foo']]
for z in lst:
z.append('bar')
lst
# [['foo', 'bar'], ['foo', 'bar']]
x.append('something')
lst
# [['foo', 'bar', 'something'], ['foo', 'bar']]
那是因为您要直接更新引用中的对象,而不是分配给object z
。但是,如果您分配x
或分配y
给新对象,lst
则不会受到影响。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句