Python 将多个变量分配给相同的值?列出行为
- 2025-02-28 08:23:00
- admin 原创
- 73
问题描述:
我尝试使用如下所示的多重赋值来初始化变量,但我对这种行为感到困惑,我希望分别重新分配值列表,我的意思是b[0]
和以前一样c[0]
相等:0
a = b = c = [0, 3, 5]
a[0] = 1
print(a) # [1, 3, 5]
print(b) # [1, 3, 5]
print(c) # [1, 3, 5]
正确吗? 我应该使用什么来进行多重赋值? 与此有何不同?
d = e = f = 3
e = 4
print(d) # 3
print(e) # 4
print(f) # 3
解决方案 1:
如果您从 C/Java/等语言家族转到 Python,它可能会帮助您不再将其视为a
“变量”,而是开始将其视为“名称”。
a
、b
和c
不是具有相等值的不同变量;它们是相同值的不同名称。变量具有类型、身份、地址以及诸如此类的东西。
名称不具备上述任何一项。当然,值具备,并且同一个值可以有很多名称。
如果你给Notorious B.I.G.
一只热狗,*Biggie Smalls
和Chris Wallace
有一只热狗。如果你将 的第一个元素改为a
1,b
和的第一个元素c
也是 1。
如果你想知道两个名称是否命名同一个对象,请使用is
运算符:
>>> a=b=c=[0,3,5]
>>> a is b
True
然后你问:
这有什么不同?
d=e=f=3
e=4
print('f:',f)
print('e:',e)
在这里,您将名称重新绑定e
到值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`
警告:不要给 Notorious BIG 喂热狗。午夜后切勿喂食黑帮说唱僵尸。
解决方案 2:
咳嗽
>>> 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'}
>>>
解决方案 3:
在 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 也会发生变化。
解决方案 4:
是的,这是预期的行为。 a
和b
都c
设置为同一列表的标签。如果您想要三个不同的列表,则需要分别分配它们。您可以重复显式列表,也可以使用多种方法之一复制列表:
# this does a shallow copy, which is good enough for this case
b = a[:]
import copy
# this does a deep copy, which matters if the list contains mutable objects
c = copy.deepcopy(a)
Python 中的赋值语句不会复制对象 - 它们将名称绑定到对象,并且对象可以具有您设置的任意数量的标签。在第一次编辑中,更改,您正在更新、和全部 引用的a[0]
单个列表的一个元素。在第二次编辑中,更改,您正在切换为另一个对象的标签(而不是)。a
`bc
ee
4`3
解决方案 5:
您可以使用它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 将会改变,因此它不会影响b
和c
的值:
>>> 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
解决方案 6:
在你的第一个例子中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
解决方案 7:
你需要的是这个:
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)
解决方案 8:
简单来说,在第一种情况下,您要为 分配多个名称list
。在内存中只会创建一个列表副本,并且所有名称都引用该位置。因此,使用任何名称更改列表实际上都会修改内存中的列表。
在第二种情况下,会在内存中创建相同值的多个副本。因此每个副本彼此独立。
解决方案 9:
满足我需求的代码可能是这样的:
# 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])
解决方案 10:
我更喜欢为多个变量分配相同的值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
解决方案 11:
例如:基本上a = b = 10
意味着和都a
指向b
内存10
,您可以通过id(a)
和进行测试,结果id(b)
恰好等于。a is b
`True`
is
匹配内存位置但不匹配其值,但是==
匹配值。
假设您想要将 的值a
从更新10
为5
,由于内存位置指向与 相同的内存位置,您将会体验到 的值也将由于初始声明b
而指向。5
结论是,仅当您知道后果时才使用它,否则只需使用,
单独的分配,a, b = 10, 10
并且不会因为内存位置不同而面临更新任何值的上述后果。
解决方案 12:
该行为是正确的。但是,所有变量将共享相同的引用。请注意以下行为:
>>> 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 进行不同的分配,则更改其中一个不会更改其他。
解决方案 13:
这里有两个代码供您选择:
a = b = c = [0, 3, 5]
a = [1, 3, 5]
print(a)
print(b)
print(c)
或者
a = b = c = [0, 3, 5]
a = [1] + a[1:]
print(a)
print(b)
print(c)
解决方案 14:
其他评论已经描述了观察到的行为的原因,但没有给出解决方案,这可以帮助以“类似方式”实现所需的结果,就像主题描述中给出的那样。
我会尝试一下:
import copy
s = [0,3,5] # Define a value we would like to assign
a,b,c=(copy.deepcopy(s) for _ in range(3)) # assign same value to variables a,b,c as its "deep copy"
# Same as a single line:
a,b,c=(copy.deepcopy([0,3,5]) for _ in range(3))
在我的例子中,改变a不会影响b或c。
扫码咨询,免费领取项目管理大礼包!