Почему два объекта класса, объявленные в одной строке, указывают на один объект? - PullRequest
1 голос
/ 22 сентября 2019

Я объявил два ListNode объекта как head = curr = ListNode(0).Теперь, к моему удивлению, они оба указывают на один и тот же адрес:

>>> head
<__main__.ListNode object at 0x10bf271d0>
>>> curr
<__main__.ListNode object at 0x10bf271d0>

Почему это так?Почему это не похоже на a = b = 4?

Потому что, если я внесу изменения в b, на a это не повлияет.Однако, если я внесу изменения в curr следующим образом, head сможет отследить это:

>>> curr.next = ListNode(1)
>>> curr = curr.next
>>> head
<__main__.ListNode object at 0x10bf271d0>
>>> curr
<__main__.ListNode object at 0x10bf27190>
>>> head.next
<__main__.ListNode object at 0x10bf27190>

Я понимаю, что head и curr объявляются со ссылкой науказатели (адрес) и a и b создаются путем ссылки на значение.Это правильно?

Если да, как я могу контролировать то, что объявляется с помощью ref для значения, а что объявляется с помощью ref для указателей (адреса)?

Класс ListNode, использованный выше:следующим образом:

>>> class ListNode(object):
...     def __init__(self, x):
...         self.val = x
...         self.next = None
...

РЕДАКТИРОВАТЬ: Объяснение того, чем этот вопрос отличается от изменяемой v / s неизменяемой неизменной и изменяемой типов .

Этот вопрос касается связывания иссылка на переменные, тогда как другой вопрос строго говорит о том, что Mutable и Immutable объекты в Python и их различия.Хотя последний действительно говорит о ссылках на переменные для объяснения Mutable v / s Immutable, он не учитывает сомнение, которое задается в этом вопросе, и, следовательно, для сообщества эти запутанные наблюдатели будут знать концепцию ссылок из-за этоговопрос.

Ответы [ 2 ]

1 голос
/ 22 сентября 2019

Почему это не похоже на a = b = 4?

Наоборот.Это точно , как это:

a = b = 4
print(id(a))
# 4552081648
print(id(b))
# 4552081648

Потому что, если я внесу изменения в b, a не будет затронут.Однако, если я внесу изменения в curr следующим образом, head сможет отследить это:

Вы меняете b на переназначая это, таким образом, привязывая имя к новому значению:

b = 5
print(id(b))
# 4552081680

Принимая во внимание, что в вашей модификации curr вы не повторно привязываете curr, поэтому он продолжает ссылаться нато же значение.

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

head = curr = ListNode(0)
head = ListNode(0)
head
# <__main__.ListNode at 0x10bf27118>
curr
# <__main__.ListNode at 0x10bf271d0>

… как видите, head и curr теперь относятся к разным значениям.

1 голос
/ 22 сентября 2019

Целые числа в python неизменны.Когда вы делаете:

a = b = 4
a = a + 1

a и b независимы в этом случае, потому что как только вы пытаетесь изменить a, вы фактически привязываете новый объект int к a.Вы на самом деле никогда не меняете целые числа, просто перепривязываете.

Когда вы делаете:

head = curr = ListNode(0)

Вы создаете один ListNode объект и привязываете ссылки head и curr кЭто.Они оба указывают на одно и то же место в памяти, как целые числа.Однако, поскольку ваш класс изменчив, нет причин для повторного связывания, когда происходит мутация.Это ожидаемое поведение.

РЕДАКТИРОВАТЬ - просто чтобы сделать целочисленную неизменность и повторное связывание более понятным:

a = b = 4

print(f"ID of 'a': {id(a)}")
print(f"ID of 'b': {id(b)}")

a += 1

print("\nAfter adding +1 to 'a'...")
print(f"ID of 'a': {id(a)}")
print(f"ID of 'b': {id(b)}")

Вывод:

ID of 'a': 1853646048
ID of 'b': 1853646048

After adding +1 to 'a'...
ID of 'a': 1853646064
ID of 'b': 1853646048

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...