通过切片和for循环修改Python列表?

舒克拉瓦格

我试图通过切片和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 = 6x变成[6, 2, 3, 4, 5]

5.)此版本的for循环可以修改列表:

请参阅上面的答案。现在,您直接在list而不是其代表上执行项目分配

6.)如果我将切片分配给var,则可以对其进行修改:

如果您到目前为止一直在关注,您将意识到现在正在将的实例分配给x[:2]对象y,该对象现在是list故事如下-您通过上的索引执行项目分配y,当然它将被更新。

7.)...但对原始清单没有影响:

当然。xy是两个不同的对象。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实例,而不是对象f1f2因此,即使我执行以下操作:

f1 = 'hello'
f
#  [<__main__.foo at 0x15f4b898>, <__main__.foo at 0x15f4d3c8>]

f由于foo实例保持不变,即使对象f1现在被分配了不同的值,它仍然保持不变出于同样的原因,每当对zin进行更改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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章