使用'更新嵌套列表中的元素;对于';韩元';不能在python列表中工作

使用'更新嵌套列表中的元素;对于';韩元';不能在python列表中工作,python,list,for-loop,nested,list-comprehension,Python,List,For Loop,Nested,List Comprehension,因此,我有一个4乘3的嵌套列表(4行,3列),我嵌套如下: >>> c= [x[:] for x in [[None]*3]*4] >>> print c [[None, None, None], [None, None, None], [None, None, None], [None, None, None]] 我以这种方式初始化了我的嵌套列表,因为它很好地解释了为什么其他方法不起作用。(比如c=[[None]*3]*4) 现在我想将第一行中

因此,我有一个4乘3的嵌套列表(4行,3列),我嵌套如下:

>>> c= [x[:] for x in [[None]*3]*4]
>>> print c
[[None, None, None], 
 [None, None, None], 
 [None, None, None], 
 [None, None, None]]
我以这种方式初始化了我的嵌套列表,因为它很好地解释了为什么其他方法不起作用。(比如c=[[None]*3]*4)

现在我想将第一行中的所有元素更新为0。i、 我想把所有的元素都放进去

c[0] to 0. So I tried the following:
>>> for x in c[0]: x = 0
...
>>> c
[[None, None, None], [None, None, None], [None, None, None], [None, None, None]]
>>>
如您所见,这些元素没有更新。 但是,以下方面起了作用:

>>> c[0] = [0 for x in c[0]]
>>>
>>> c
[[0, 0, 0], [None, None, None], [None, None, None], [None, None, None]]
我几乎可以肯定,这是因为我正在创建一个0的新列表,并将其分配给c[0]

无论如何,我随后继续使用for循环,并尝试将第一列(即每行的第一个元素)更新为0,结果成功了

>>> for x in c: x[0] = 0
...
>>> c
[[0, None, None], [0, None, None], [0, None, None], [0, None, None]]
我知道这个for循环更新与之前的for循环更新不同,因为第一个for循环更新尝试在单个元素上循环,而这个for循环更新在列表上循环,并且只访问每个列表的第一个元素

我肯定我遗漏了一些指向其他名字的名字,但我无法指出确切的问题是什么。有人能帮忙吗

for x in c[0]: x = 0
在这个循环中,您实际上是在创建对该列表中存在的整数的新引用,然后更改这些新引用

由于整数是不可变的,所以原始引用不会受到影响。另外,由于赋值不是就地操作,所以这也不会影响可变对象

>>> a = b = 1
>>> b += 1     # in-place operation, this will work differently for mutable objects
>>> a, b       # a is still unchanged
(1, 2)
赋值操作也不会影响可变对象:

>>> x = y = [1, 1]
>>> x = 2 # `x` now points to a new object, number of references to [1, 1] decreased by 1
>>> x, y
(2, [1, 1])
但就地操作将:

>>> x = y = [1, 1]
>>> x.append(2)
>>> x, y
([1, 1, 2], [1, 1, 2])
因此,上述循环实际上相当于:

x = c[0]
x = 0    #this won't affect `c[0]`
x = c[1]
x = 0
...

在这个循环中,您实际上将c[0]更改为指向一个新的列表对象:

>>> c= [x[:] for x in [[None]*3]*4]
>>> c= [x[:] for x in [[None]*3]*4]
>>> print id(c[0])
45488072
>>> c[0] = [0 for x in c[0]]
>>> print id(c[0])              #c[0] is a new list object
45495944

在每种情况下,
x
都是对某物的引用

在引用
None
的情况下,您正在创建
int(0)
的实例,并切换
x
以引用该实例。所以这里根本不涉及
c

在其他情况下,
x
是对
c
组件的引用,因此当您修改该组件时,可以看到反映在
c
中的更改

现在我想将第一行中的所有元素更新为0。i、 e.我想将
c[0]
中的所有元素设置为0。因此,我尝试了以下方法:

如您所见,这些元素没有更新

这是因为
x
在c[0]中依次给出了每个
None
值,所以您实际上是在说:

x = None
x = 0
x = None
x = 0
x = None
x = 0
这没有任何用处

但是,以下方面起了作用:

>>> c[0] = [0 for x in c[0]]
>>>
>>> c
[[0, 0, 0], [None, None, None], [None, None, None], [None, None, None]]
我几乎可以肯定,这是因为我正在创建一个0的新列表,并将其分配给c[0]

这是因为
c[0]
是对
c
中第一个元素(列表)的引用或别名。。。您可以将新值赋给它,它会影响原始的
c
容器。这里最关键的是“直写引用/别名”思想。我不确定Python社区通常称之为什么(我主要是C++程序员),但是功能上你的<代码> C(0)< /代码>引用了<代码> C < />代码中的元素,并允许你覆盖它。code>c[0]与上面的
x
不同,因为
x
有效地看到了元素值的不可变副本(
None
),但该值与容器
c
没有任何连接,也无法写回容器。这是因为
None
是一个简单的“标量”值

变量有时有效地引用分配给它们的值的不可变副本,而进一步的分配将使它们与之分离,而其他时候实际上继续引用分配的值本身,这样进一步的写入就可以修改它,这种想法实际上在几种解释语言中是常见的(例如,Ruby也这么做)。起初它很混乱!这些语言希望你认为它们比C++更简单,在这些“引用”中使用。它们是明确的,并且有自己的语法/符号,但事实上,你很快就会被咬到,并且无论如何都必须学会理解它们之间的区别,然后当你需要真正独立的数据拷贝时,就开始使用
copy.deepcopy
。它们希望看起来直观,但直观的东西——深度拷贝值——对于大型数据来说太昂贵了ER和对象:大多数新手的程序会变得非常慢,他们不知道为什么。因此,现代脚本语言倾向于采用这种危险的行为,让你写一些你可能认为你已经安全地从中复制了一些数据的东西。使用这种语言几周后,它可能会全部点击……而我首先令人困惑的是,它实际上也很有用——必须使用原始变量名引用数据,所有的键和索引都要缩小到一个特定的标量值,这可能会令人痛苦地冗长,当然,这是一个必要的抽象,允许函数对复杂对象/容器的某些部分进行操作,而不需要h渴望了解对象的其余部分

无论如何,我随后继续使用for循环,并尝试将第一列(即每行的第一个元素)更新为0,结果成功了

这是因为
x
被依次绑定为每个列表的引用/别名,并且列表是“复杂”对象,引用/别名允许我上面描述的写通功能

我知道这个for循环更新与之前的for循环更新不同,因为第一个for循环更新尝试在单个元素上循环,而这个for循环更新在列表上循环,并且只访问每个列表的第一个元素


整数是不可变的,因此:
a=b=1;b+=1
不会影响
a
。我确实理解在Python中整数和字符串是不可变的,但我恐怕不理解这在这个问题的上下文中意味着什么。请您详细说明一下,为什么不使用索引,通常在迭代时无法更改列表我
>>> c[0] = [0 for x in c[0]]
>>>
>>> c
[[0, 0, 0], [None, None, None], [None, None, None], [None, None, None]]
>>> for x in c: x[0] = 0
...
>>> c
[[0, None, None], [0, None, None], [0, None, None], [0, None, None]]