Подтвердить что ты не робот

Почему переменная = объект не работает, как variable = number

Эти назначения переменных работают так, как я ожидаю:

>>> a = 3
>>> b = a
>>> print(a, b)
(3, 3)
>>> b=4
>>> print(a, b)
(3, 4)

Однако эти назначения ведут себя по-другому:

>>> class number():
...     def __init__(self, name, number):
...         self.name = name
...         self.number = number
... 
>>> c = number("one", 1)
>>> d = c
>>> print(c.number, d.number)
(1, 1)
>>> d.number = 2
>>> print(c.number, d.number)
(2, 2)

Почему c совпадает с d, в отличие от примера (a, b)? Как я могу сделать что-то вроде примера (a, b) в (c, d)? То есть, скопируйте объект, а затем измените его часть (что не повлияет на объект, который я заимствовал свойства)?

4b9b3361

Ответ 1

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

import copy
c = number("one", 1)
d = c
e = copy.copy(c)

print(c.number, d.number, e.number)
d.number = 2
e.number = 5
print(c.number, d.number, e.number)

Это даст вам:

1 1 1
2 2 5

Ответ 2

Эти строки:

c = number("one", 1)
d = c

... эффективно:

  • Создайте новый экземпляр number и назначьте его c
  • Назначьте существующую ссылку под названием c новой переменной d

Вы ничего не изменили и не модифицировали c; d - это другое имя, указывающее на тот же экземпляр.

Без клонирования экземпляра или создания нового экземпляра вы не можете сделать ничего похожего на поведение примитива int.


Чтобы исправить немного информации, приведенное выше объяснение довольно упрощено и немного неполное по своей природе, хотя он в основном описывает то, что происходит на высоте 10 000 футов.

Для более пристального изучения нам нужно понять несколько вещей о переменных Python или "именах" и о том, как они взаимодействуют с этой программой.

Как уже упоминалось выше, у вас есть понятие "имена" и "привязки" , которые довольно просто рассуждать по адресу:

a = 3
b = a

В этом контексте a - это имя, а b является привязкой к a. Мы ничего и не изменили и не изменили о a.

Как отмечалось ранее, в Python имеются два типа данных: изменчивый и неизменный. Имя, указывающее на неизменяемые данные, такие как примитивы и кортежи, может быть переназначено без каких-либо вредных последствий для любых других привязок, присутствующих на нем, потому что ни одно состояние не меняется в отношении привязки.

Вот почему это переназначение делает то, что мы ожидаем от него:

print(a, b)
b = 4
print(a, b)

Результатом b = 4 является то, что b теперь указывает на новую копию целого числа, значение 4.

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

t = ('foo', 'bar')
t[0] = 'baz' # illegal

... но вы можете иметь изменяемые структуры данных как часть этих привязок.

t = ([1, 2, 3], 'bar')
t[0].append([4, 5, 6]) # ([1, 2, 3, [4, 5, 6]], 'bar')

Итак, где это может оставить наш пример?

c = number("one", 1)
d = c

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

Фактически у нас есть имя и привязка к имени:

  • У нас есть новый экземпляр number и ссылайтесь на него по имени c.
  • Привяжите ссылку c к другому имени d.

Снова ничего не изменилось в c, но на него можно ссылаться с помощью другого имени.

В отличие от неизменяемых данных, когда мы переназначаем значение d.number, мы переназначаем ту же привязку, о которой c знает:

>>> id(d.number)
36696408
>>> id(c.number)
36696408

Вот почему требуется новый экземпляр или копия. Вы должны обратиться к другому экземпляру number. С помощью этой простой привязки вы не достигнете этого.

from copy import copy
c = number("one", 1)
d = copy(c)
id(c) # 140539175695784
id(d) # 140539175695856

Ответ 3

Изображение на тысячу слов

a = 3
b = a
c = number("one", 1)
d = c

Block-and-pointer diagram, before


Шаг 2...

b = 4
d.number = 2

Block-and-pointer diagram, after

Вы можете понять, почему изменение d.number также повлияет на c.


Если до этапа 2 вы выполняете

import copy
d = copy.copy(c)

... тогда c и d независимы. Изменение d.number не повлияет на c.

Block-and-pointer diagram, after copying

Ответ 4

Вы фокусируетесь на том, что эти две пары строк одинаковы (оба используют plain =):

# one
a = 3
b = a

#two
c = number("one", 1)
d = c

Что вам не хватает, так это то, что эти две строки разные:

# one
b = 4

# two
d.number = 2

Причина, по которой они не совпадают, заключается в том, что d.number имеет в ней точку, а b - нет.

Настройка d = c имеет тот же эффект, что и установка b = a. Разница в том, что выполнение d.number = 2 не совпадает с выполнением b = 4. Когда вы выполняете b = 4, вы назначаете новый объект имени b. Когда вы выполняете d.number = 2, вы изменяете объект, на который уже ссылается имя d, не назначая новый объект. Если вы измените свой второй пример на d = 2, используя простое назначение вместо назначения атрибута, вы увидите, что c не изменяется, так же как a не влияет на ваш первый пример.

Хотя это может запутать, = не всегда означает одно и то же во всех контекстах на Python. Присвоение голого имени (blah = ...) не совпадает с назначением атрибута (blah.attr = ...) или элемента (blah[item] = ...). Чтобы понять, что означает =, вам нужно посмотреть на левую сторону (цель назначения), чтобы увидеть, является ли это голое имя или какое-то выражение.

Что касается того, как получить эффект вашего примера a/b в примере c/d, это зависит от того, какой именно эффект вы хотите. Если вы хотите включить d и c, указывая на разные объекты с разными атрибутами number, вы можете сделать:

d = number("one", 2)

Обратите внимание, что теперь он параллелен b = 4 (потому что он использует назначение для голого имени). Существуют и другие более сложные решения, связанные с созданием копии существующего объекта d; посмотрите на copy модуль в стандартной библиотеке. То, что нужно делать, зависит от того, что вы пытаетесь выполнить с помощью кода.

Ответ 5

В Python все является ссылкой. Возьмите это, например:

a = '1221398210p3'
b = a
print(id(a) == id(b)) # True

Теперь, когда вы это сделаете:

b = 4

вы просто меняете ссылки на номер b. Не сам номер. Теперь, в следующем примере:

c = number("one", 1)
d = c
...
d.number = 2

d = c устанавливает d для ссылки c. Теперь, когда вы устанавливаете d.number, вы устанавливаете атрибут объекта, который ссылается на c и d. Как я уже сказал, все является ссылкой.

В Python переменные больше похожи на метки (или в терминах C, указатели): они не являются значениями. Они просто указывают на реальную ценность.

Ответ 6

Причиной этого различия является неизменяемый v. неизменяемые объекты - int - неизменяемый объект, ваш класс - изменяемый объект.

В этом примере (как и в первом примере) оба x и y указывают тот же неизменяемый объект (целое число, 1). Этот объект никогда не может измениться, поэтому, когда вы назначаете y = 2, y теперь указывает на другой неизменный объект (int(2)).

>>> x = 1  # x points to the object int(1).
>>> y = x  # So does y.
>>> assert x is y
>>> y = 2
>>> assert x is not y
>>>    

Ваш класс является изменяемым объектом, похожим на список. В этом втором примере (аналогично вашему второму примеру) оба x и y указывают на один и тот же изменяемый объект ([]). Когда вы добавляете к нему 0, он помещает его в список, который они оба ссылаются. Когда вы назначаете [0] на y, вы назначаете другой список y, но этот список оказывается равным x, даже если это другой объект.

>>> x = []
>>> y = x
>>> assert x is y  # x and y reference the same object.
>>> y.append(0)  # We append 0 to the list that both x and y reference.
>>> x
[0]
>>> y
[0]
>>>
>>> y = [0]  # Creating a new list object.
>>> assert x is not y  # x and y are different objects...
>>> assert x == y  # ...but they are equal.
>>>    

Ответ 7

"Что во имя? то, что мы называем розой

Другим именем будет пахнуть как сладкий;

--- Акт II, Сцена II Ромео Джульетта

В Python

  • переменная является просто символической ссылкой на объект или литерал
  • объект является экземпляром типа или класса
  • если явно не принудительно, все переменные копируются посредством ссылки (назначения, передача параметров и возвращаемое значение функции)

Теперь давайте понять ваш пример

a и b относятся к двум различным целым литералам

a = 3
b = a

print(a, b)

b теперь ссылается на новый целочисленный литерал (4)

b=4

c относится к объекту, который является экземпляром класса number

c = number("one", 1)

d ссылается на тот же объект, что c указывает на

d = c

Измените атрибут числа объекта, на который ссылается d. Поскольку d и c ссылаются на один и тот же объект, это также влияет на c.

d.number = 2

Ответ 8

Почему c то же, что и d, в отличие от примера (a, b)?

В python переменная не является объектом.
"Гамлет не был написан Шекспиром, он был написан просто человеком по имени Шекспир". Python делает важное различие между вещью и ярлыком, который мы используем для обозначения этой вещи. "Человек по имени Шекспир" - это человек. "Шекспир" - это просто имя. Если мы это сделаем:

l = []

то [] - пустой список. l - это переменная, указывающая на пустой список, но l сама по себе не является пустым списком.

enter image description here

Итак, в python переменные работают скорее как тег. Когда вы выполняете задание в Python, оно тегирует значение с именем переменной.

a = 1

enter image description here

и если вы измените значение переменной, оно просто изменит тег на новое значение в памяти.

enter image description hereenter image description here

Назначение одной переменной другому означает, что новый тег привязан к тому же значению, что показано ниже.

b = a  

enter image description here

Если вы назначаете новое значение 3 на b, то оно будет привязано к тому, что новое значение и a все равно будут привязаны к 2.

Во втором фрагменте d = c сделает оба c и d, чтобы указать на один и тот же объект. Изменение любого члена объекта приведет к тому, что этот член укажет на новое значение, а не на имя a и b. Они все равно будут указывать на один и тот же объект.

Как я могу сделать что-то вроде примера (a, b) в (c, d)? То есть скопируйте объект и затем измените его часть (что не повлияет на объект, заимствованный у меня из объектов)?

Python 2.7.10: 8.17. copy - операции с мелкой и глубокой копией:

Операторы присваивания в Python не копируют объекты, они создают привязки между объектом и объектом. Для коллекций, которые изменяются или содержат изменяемые элементы, иногда требуется копия, поэтому можно изменить одну копию, не изменяя другую. Этот модуль предоставляет общие мелкие и глубокие операции копирования (поясняется ниже).

Сводка интерфейса:

copy.copy(x)

Верните мелкую копию x.

copy.deepcopy(x)

Верните глубокую копию x.

>>> import copy
>>> c = number("one", 1)
>>> d = copy.copy(c)        # Make a copy of object c  
>>> id(d), id(c)
(42898856, 43279384)  

Изменение любого из объектов c или d не будет влиять друг на друга.


Ссылки:

Ответ 9

Назначение ссылки объекта на переменную точно так же, как присвоение числа переменной. Ни один из них не требует копирования чего-либо. Это точно так же в интеллектуальных предках Python Lisp и Smalltalk. Просто случается, что числа не могут быть изменены.

>>> x = 10**50
>>> y = 10**50
>>> z = x
>>> x is y
False
>>> x is z
True

Мы видим здесь, что Python различает между копированием (x и y равны, но различны) и не делает копию (x is z), и что присвоение номера не делает копию.

Ответ 10

Это не было выяснено в других ответах, но если я правильно помню, целые числа в python на самом деле не являются примитивами. Они являются неизменяемыми целыми объектами. Поэтому, когда у вас есть несколько переменных, все из которых имеют значение 3, на самом деле у вас есть несколько ссылок на единственный экземпляр Integer, который содержит значение 3.

Таким образом, имея в виду,

a = 3
b = a

Результаты в переменных a и b, каждая из которых указывает на целое число, содержащее значение 3. Аналогично,

c = number("one", 1)
d = c

Результаты в переменных c и d, каждая из которых указывает на один и тот же экземпляр числа.

То же самое происходит с

b = 4

Теперь b является ссылкой на Integer 4.

Однако, когда d.number установлен

d.number = 2

Членная переменная "число" экземпляра класса "число", на которую указывают как c, так и d, обновляется для ссылки на Integer 2. Важное понятие здесь заключается в том, что вы изменяете переменную-член объект, на который ссылаются две отдельные переменные.

Источники: http://www.laurentluce.com/posts/python-integer-objects-implementation/