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)]