Reputation: 4582
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.
Upvotes: 1
Views: 58
Reputation: 545923
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 tocurr
in the following manner, thehead
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.
Upvotes: 1
Reputation: 10809
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.
Upvotes: 1