Как точно работает копирование в Python?

Почему это так:

>>> a = 1 >>> b = a >>> a = 2 >>> print(a) 2 >>> print(b) 1 

…но:

  >>> a = [3, 2, 1] >>> b = a >>> a.sort() >>> print(b) [1, 2, 3] 

Я имею в виду, почему переменные действительно скопированы, и итераторы просто ссылаются?

Переменные не «действительно скопированы». Переменные – это имена для объектов, а оператор присваивания связывает имя с объектом в правой части оператора. Более подробно:

>>> a = 1 означает «сделать имя, относящееся к объекту 1 ».

>>> b = a означает «сделать b имя, относящееся к объекту, на который в настоящее время ссылается a . Который равен 1 .

>>> a = 2 означает «сделать имя, относящееся к объекту 2 ». Это не влияет на какой объект, к которому теперь относится что-либо еще, связанное со ссылкой на 1 , например, b .

В вашем втором примере оба a и b являются именами, относящимися к одному и тому же объекту списка. a.sort() мутирует этот объект на месте, и поскольку обе переменные относятся к одному и тому же объекту, эффекты мутации видны под обоими именами.

Подумайте о назначенных переменных в качестве указателей на ячейку памяти, где хранятся значения. Фактически вы можете получить ячейку памяти, используя id .

 a = 1 b = a >>> id(a) 4298171608 >>> id(b) 4298171608 # points to the same memory location a = 2 >>> id(a) 4298171584 # memory location has changed 

Выполняя то же самое с примером списка, вы можете видеть, что оба они фактически работают на одном и том же объекте, но с разными переменными, указывающими на одно и то же место в памяти.

 a = [3, 2, 1] b = a a.sort() >>> id(a) 4774033312 >>> id(b) 4774033312 # Same object 

в первом примере вы переназначили значение a после значения b a. поэтому a и b несут разные значения.

то же самое произошло бы во втором примере, если бы вы переназначили a в новый отсортированный список, а не просто сортировали его на месте.

 a = [3,2,1] b = a a.sort() print b [1,2,3] 

но…

 a = [3,2,1] b = a sorted(a) print b [3,2,1]