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)