Python присваивает нескольким переменным одинаковое значение? поведение списка
Я попытался использовать множественное назначение как показано ниже для инициализации переменных, но я запутался в поведении, я ожидаю переназначить список значений отдельно, я имею в виду, что 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)
Ответы
Ответ 1
Если вы приходите на Python с языка в C/Java/etc. семья, это может помочь вам перестать думать о 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
.
user570826 спросил:
Что делать, если у нас есть a = b = c = 10
Точно такая же ситуация, как a = b = c = [1, 2, 3]
: у вас есть три имени для одного и того же значения.
Но в этом случае значение равно int
, а int
неизменяемы. В любом случае вы можете перестроить a
на другое значение (например, a = "Now I'm a string!"
), но это не повлияет на исходное значение, для которого b
и c
по-прежнему будут именами. Разница в том, что со списком вы можете изменить значение [1, 2, 3]
на [1, 2, 3, 4]
, выполнив, например, a.append(4)
; так как фактически изменение значения, которое b
и c
являются именами, b
теперь будет b [1, 2, 3, 4]
. Невозможно изменить значение 10
на что-либо еще. 10
10 навсегда, точно так же, как Клаудия вампир 5 навсегда (по крайней мере, пока она не заменит Кирстен Данст).
* Предупреждение: не давайте Notorious B.I.G. хот-дог. Gangsta rap зомби никогда не следует кормить после полуночи.
Ответ 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
Да, это ожидаемое поведение. 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 не копируют объекты - они связывают имя с объектом, а объект может иметь столько ярлыков, сколько вы установили. В первом редактировании, изменяя значение [0], вы обновляете один элемент единственного списка, к которому относятся все a, b и c. Во втором, изменяя e, вы переключаете e на метку для другого объекта (4 вместо 3).
Ответ 4
В python все является объектом, а также "простыми" типами переменных (int, float и т.д.).
Когда вы меняете значение переменной, вы фактически меняете его указатель, и если вы сравниваете две переменные, он сравнивает свои указатели.
(Чтобы быть ясным, указатель - это адрес в памяти физического компьютера, где хранится переменная).
В результате, когда вы изменяете значение внутренней переменной, вы изменяете ее значение в памяти и воздействуете на все переменные, указывающие на этот адрес.
В вашем примере, когда вы делаете:
a = b = 5
Это означает, что a и b указывают на тот же адрес в памяти, который содержит значение 5, но когда вы это делаете:
a = 6
Это не влияет на b, потому что теперь указывает на другое место памяти, которое содержит 6 и b, все еще указывает на адрес памяти, содержащий 5.
Но когда вы это сделаете:
a = b = [1,2,3]
a и b снова указывают на одно и то же место, но разница в том, что если вы измените одно из значений списка:
a[0] = 2
Он изменяет значение памяти, на которое указывает точка a, но a все еще указывает на тот же адрес, что и b, и в результате также изменяется b.
Ответ 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
, тогда его идентификатор изменится, поэтому он не повлияет на значения 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
У меня была похожая проблема с TKInter при инициализации нескольких переменных одним и тем же методом:
e_serverIP, e_serverPort, e_user, e_password = [Entry(master) for k in range(4)]