1

I declared two ListNode objects as head = curr = ListNode(0). Now, to my surprise, both of them point at the same address:

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

Why is that? Why is it not like a = b = 4?

Because, if I make changes to b, a doesn't get affected. However, if I make changes to curr in the following manner, the head can keep a track of it:

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

I understand that head and curr are declared by refercing to pointers(address) and a and b are made by referencing to value. Is that right?

If yes, how can I control what gets declared with ref to value and what gets declared with ref to pointers(address)?

The ListNode class used above is as follows:

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

EDIT: Explanation of how this question is different from Mutable v/s Immutable Immutable vs Mutable types.

This question addresses the binding and referencing of the variables whereas the other question strictly talks about what Mutable and Immutable objects are in Python and their differences. While the latter does tell about the referencing of variables in order to explain Mutable v/s Immutable, it does not address the doubt that is asked in this question and hence, for the community, those confused observers would know the referencing concept due to this question.

Aviral Srivastava
  • 4,058
  • 8
  • 29
  • 81
  • `a` and `b` are `int` here, which is immutable, while `ListNode` is mutable. So if you want `head` and `curr` to point to different address, create two new objects like `head, curr = ListNode(0), ListNode(0)` – han solo Sep 22 '19 at 15:00
  • 1
    Possible duplicate of [Immutable vs Mutable types](https://stackoverflow.com/questions/8056130/immutable-vs-mutable-types) – Maurice Meyer Sep 22 '19 at 15:01
  • @MauriceMeyer, just curious, how would a person who observes the same issue would be able to reach out to the concept of Mutable v/s Immutable? – Aviral Srivastava Sep 22 '19 at 15:07

2 Answers2

1

Integers in python are immutable. When you do:

a = b = 4
a = a + 1

a and b are independent in this case, because as soon as you try to mutate a, you are actually binding a new int object to a. You're never actually changing integers, just rebinding.

When you do:

head = curr = ListNode(0)

You create one ListNode object, and bind the references head and curr to it. They're both pointing to the same place in memory, just like the integers. However, since your class is mutable, there is no reason to rebind when a mutation occurs. This is the expected behavior.

EDIT - Just to make integer immutability and rebinding a bit clearer:

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)}")

Output:

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

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

You can see that attempting to mutate a doesn't change the underlying integer object - it simply rebinds a to a new integer object.

Paul M.
  • 10,481
  • 2
  • 9
  • 15
  • That really explained well. Thank you so much @user10987432 – Aviral Srivastava Sep 22 '19 at 15:06
  • do you think the question is clear enough for someone who is a confused observant? If yes, please upvote it. If not, please let me know what am I missing? Thanks! – Aviral Srivastava Sep 22 '19 at 15:10
  • 1
    Glad my answer was helpful. I think your question is pretty clear. – Paul M. Sep 22 '19 at 15:13
  • 1
    Immutability has *nothing whatsoever* to do with this, and referring to it is immensely misleading. The same can be achieved with mutable types. The relevant difference is that “modification” in the two cases is achieved by completely different means (rebinding, and in-place modification). – Konrad Rudolph Sep 22 '19 at 15:48
1

Why is it not like a = b = 4?

On the contrary. It’s exactly like it:

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

Because, if I make changes to b, a doesn't get affected. However, if I make changes to curr in the following manner, the head can keep a track of it:

You’re changing b by reassigning it, thus rebinding the name to a new value:

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

Whereas, in your modification of curr, you’re not rebinding curr so it keeps referring to the same value.

Contrary to common misconception, this has nothing to do with immutability: you can of course rebind names to mutable values just fine:

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

… as you can see, head and curr now refer to different values.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214