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)

14 ответов

Решение

Если вы пришли на Python с языка в C/Java/ и т.д. семья, это может помочь вам перестать думать о 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 теперь будет б [1, 2, 3, 4], Там нет никакого способа изменить значение 10 во что-нибудь еще. 10 10 навсегда, точно так же как Клаудия вампир 5 навсегда (по крайней мере, пока ее не заменит Кирстен Данст).


* Предупреждение: не давайте Notorious BIG хот-дог. Гангста-рэп зомби никогда не следует кормить после полуночи.

Кашель кашель

>>> 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'}
>>> 

В 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, но a по-прежнему указывает на тот же адрес, что и b, и в результате b также изменяется.

Да, это ожидаемое поведение. 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).

Ты можешь использовать 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

В вашем первом примере 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

Надеюсь это поможет!

Проще говоря, в первом случае вы присваиваете несколько имен list, В памяти создается только одна копия списка, и все имена относятся к этому месту. Таким образом, изменение списка с использованием любого из имен фактически изменит список в памяти.

Во втором случае несколько копий одного значения создаются в памяти. Таким образом, каждая копия не зависит друг от друга.

Что вам нужно, это:

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)

Спасибо всем за разъяснения.

код, который делает то, что мне нужно, может быть таким:

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

С уважением

Чтобы присвоить нескольким переменным одно и то же значение, я предпочитаю 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

Например: в основномa = b = 10означает оба и указывают в памяти, вы можете проверитьid(a)иid(b)что выходит в точности равнымa is bкакTrue.

isсоответствует ячейке памяти, но не ее значению, однако==соответствует значению.

предположим, вы хотите обновить значениеaот10на , так как ячейка памяти указывала на ту же ячейку памяти, вы испытаете значениеbтакже будет указывать на5из-за первоначального объявления.

Вывод состоит в том, чтобы использовать это только в том случае, если вы знаете последствия, в противном случае просто используйте,отдельное задание, напримерa, b = 10, 10и не столкнется с описанными выше последствиями при обновлении любого из значений из-за разных мест памяти.

Причина наблюдаемого поведения уже была описана в других комментариях, но не было дано решение, которое могло бы помочь достичь требуемого результата "аналогичным способом", как это было указано в описании темы.
Я бы попробовал:

      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 .

Поведение правильное. Однако все переменные будут иметь одну и ту же ссылку. Обратите внимание на поведение ниже:

      >>> 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 по-разному в отдельной строке, изменение одного не изменит другие.

Вот два кода для вас, чтобы выбрать один:

      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)
Другие вопросы по тегам