162

我尝试使用如下所示的多重赋值来初始化变量,但我对这种行为感到困惑,我希望单独重新分配值列表,我的意思是 b[0] 和 c[0] 像以前一样等于 0。

a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)

结果是: [1, 3, 5] [1, 3, 5] [1, 3, 5]

那是对的吗?我应该使用什么进行多重分配?与此有何不同?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

结果: ('f:', 3) ('e:', 4)

4

11 回答 11

307

如果您是从 C/Java/etc 中的语言开始使用 Python。家庭,它可能会帮助您停止将a其视为“变量”,而开始将其视为“名称”。

a, b, 和c不是具有相同值的不同变量;它们是相同值的不同名称。变量有类型、身份、地址和各种类似的东西。

名字没有这些。当然,值确实如此,并且您可以为相同的值有很多名称。

如果你给Notorious B.I.G.一个热狗,*Biggie SmallsChris Wallace有一个热狗。如果将 的第一个元素更改a为 1,则b和的第一个元素为c1。

如果您想知道两个名称是否命名同一个对象,请使用is运算符:

>>> a=b=c=[0,3,5]
>>> a is b
True

然后你问:

与此有何不同?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

在这里,您将 name 重新绑定e到 value 4。这不会以任何方式影响d名称f

在您以前的版本中,您分配给a[0],而不是a。因此,从 的角度来看a[0],您正在重新绑定a[0],但从 的角度来看a,您正在就地更改它。

您可以使用该id函数为您提供一些表示对象身份的唯一编号,以准确查看哪个对象是哪个对象,即使is无法提供帮助:

>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120

>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216

请注意,a[0]它已从 4297261120 更改为 4297261216——它现在是不同值的名称。并且b[0]现在也是相同新值的名称。那是因为a并且b仍在命名同一个对象。


在幕后,a[0]=1实际上是调用列表对象上的一个方法。(它相当于a.__setitem__(0, 1).)所以,它根本没有真正重新绑定任何东西。就像打电话一样my_object.set_something(1)。当然,对象可能正在重新绑定实例属性以实现此方法,但这不是重要的;重要的是你没有分配任何东西,你只是在改变对象。和它一样a[0]=1


用户570826问:

如果我们有,a = b = c = 10

这与 完全相同的情况a = b = c = [1, 2, 3]:您有相同值的三个名称。

但在这种情况下,值是 a int,并且ints 是不可变的。在任何一种情况下,您都可以重新绑定a到不同的值(例如,a = "Now I'm a string!"),但不会影响原始值,它b仍然c是名称。不同之处在于,使用列表,您可以通过执行将值更改[1, 2, 3][1, 2, 3, 4],例如a.append(4); 因为这实际上改变了bc名称的值,所以b现在将 b [1, 2, 3, 4]。没有办法将值更改10为其他任何值。10永远是 10,就像吸血鬼克劳迪娅永远是 5(至少在她被克尔斯滕·邓斯特取代之前)。


* 警告:不要给 Notorious BIG 热狗。黑帮说唱僵尸不应该在午夜之后被喂食。

于 2013-05-02T23:27:16.010 回答
92

咳嗽

>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>> 
于 2014-02-06T22:36:30.500 回答
16

在 python 中,一切都是对象,也是“简单”变量类型(int、float 等)。

当你改变一个变量的值时,你实际上改变了它的指针,如果你在两个变量之间进行比较,它就是比较它们的指针。(要清楚,指针是物理计算机内存中存储变量的地址)。

结果,当您更改内部变量值时,您会更改它在内存中的值,并且会影响指向该地址的所有变量。

对于您的示例,当您这样做时:

a = b =  5 

这意味着 a 和 b 指向内存中包含值 5 的相同地址,但是当您这样做时:

a = 6

它不会影响 b,因为 a 现在指向另一个包含 6 的内存位置,而 b 仍然指向包含 5 的内存地址。

但是,当你这样做时:

a = b = [1,2,3]

a 和 b 再次指向相同的位置,但不同之处在于,如果您更改列表值之一:

a[0] = 2

它改变了 a 指向的内存的值,但 a 仍然指向与 b 相同的地址,因此 b 也发生了变化。

于 2013-05-02T22:46:32.217 回答
14

是的,这是预期的行为。a、b 和 c 都设置为同一列表的标签。如果您想要三个不同的列表,则需要单独分配它们。您可以重复显式列表,或使用多种方法之一来复制列表:

b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects

Python 中的赋值语句不会复制对象——它们将名称绑定到对象,并且对象可以具有您设置的任意数量的标签。在您的第一次编辑中,更改 a[0],您正在更新 a、b 和 c 都引用的单个列表的一个元素。在第二次更改 e 时,您将 e 切换为不同对象的标签(4 而不是 3)。

于 2013-05-02T22:41:21.647 回答
12

您可以使用id(name)来检查两个名称是否代表同一个对象:

>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488

列表是可变的;这意味着您可以在不创建新对象的情况下就地更改值。但是,这取决于您如何更改值:

>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]

如果您为 分配一个新列表a,那么它的 id 将会改变,因此它不会影响bandc的值:

>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]

整数是不可变的,因此您不能在不创建新对象的情况下更改值:

>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1
于 2013-05-02T22:48:10.330 回答
7

在您的第一个示例中,a = b = c = [1, 2, 3]您实际上是在说:

 'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]

如果你想设置 'a' 等于 1,'b' 等于 '2' 和 'c' 等于 3,试试这个:

a, b, c = [1, 2, 3]

print(a)
--> 1
print(b)
--> 2
print(c)
--> 3

希望这可以帮助!

于 2013-05-02T22:36:00.483 回答
4

简单地说,在第一种情况下,您将多个名称分配给一个list. 在内存中只创建了一份 list 副本,所有名称都指向该位置。因此,使用任何名称更改列表实际上会修改内存中的列表。

在第二种情况下,在内存中创建了多个相同值的副本。所以每个副本都是相互独立的。

于 2016-01-30T05:28:25.390 回答
3

你需要的是这样的:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1             # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)
于 2013-05-02T22:35:37.633 回答
3

做我需要的代码可能是这样的:

# test

aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)

# initialization

a,b,c,d=[[0 for n in range(3)] for i in range(4)]

# changing values

a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)

结果:

('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
于 2013-05-03T04:02:52.653 回答
0

行为是正确的。但是,所有变量都将共享相同的引用。请注意以下行为:

>>> a = b = c = [0,1,2]
>>> a
[0, 1, 2]
>>> b
[0, 1, 2]
>>> c 
[0, 1, 2]
>>> a[0]=1000
>>> a
[1000, 1, 2]
>>> b
[1000, 1, 2]
>>> c
[1000, 1, 2]

所以,是的,如果你在单独的行上以不同的方式分配 a、b 和 c,那么改变一个不会改变其他的。

于 2022-01-05T04:47:40.100 回答
0

我更喜欢为多个变量分配相同的值list

a, b, c = [10]*3#multiplying 3 because we have 3 variables
print(a, type(a), b, type(b), c, type(c))

输出:

10 <class 'int'> 10 <class 'int'> 10 <class 'int'>

初始化多个对象:

import datetime

time1, time2, time3 = [datetime.datetime.now()]*3

print(time1)
print(time2)
print(time3)

输出:

2022-02-25 11:52:59.064487
2022-02-25 11:52:59.064487
2022-02-25 11:52:59.064487
于 2022-02-25T06:26:04.033 回答