4

Suppose I assign two variables to integers:

a = 1
b = 2

Now, I'll assign a to b:

a = b

As expected, a == 2, because a has been set to the memory address of b.

But actually, it hasn't. If I do

b += 1

a still equals 2. Why does a not point to b?

imposeren
  • 4,142
  • 1
  • 19
  • 27
Alec
  • 8,529
  • 8
  • 37
  • 63
  • It hasn’t been set to the memory address. Its value has been set. They’re just variables, not pointers. – Sami Kuhmonen May 13 '19 at 04:09
  • So assigning one variable to another simply sets the first variable to the value of the second variable and nothing more? That doesn't seem to always be the case – Alec May 13 '19 at 04:10
  • for integers and floats it copies value from one variable to another. For more complex structures - like list, dictionary, class - it copies reference and you may get expected result. You can use [PythonTutor](http://pythontutor.com/) to visualize it. – furas May 13 '19 at 04:12
  • i think this link is useful for you. https://stackoverflow.com/questions/37535694/why-are-integers-immutable-in-python – LambdaG May 13 '19 at 04:15

3 Answers3

4

The behavior in the example is as follows

In [1]: a = 1                                                                                                                                                                     

In [2]: b = 2                                                                                                                                                                     

In [3]: a = b                                                                                                                                                                     

In [4]: b+=1                                                                                                                                                                      

In [5]: b                                                                                                                                                                         
Out[5]: 3

In [6]: a                                                                                                                                                                         
Out[6]: 2

In the example, when you do a=b, both a and b are pointing to the same reference, but when you b += 1, the operation of adding 1 to b, creates a new integer value 3 for b and b points to that value, but a is still pointing to the old value 2

Note that trying to do it with mutable types like a list works as what you were excepting would happen to an integer

In [1]: a = [1]                                                                                                                                                                   

In [2]: b = [2]                                                                                                                                                                   

In [3]: a = b                                                                                                                                                                     

In [4]: b.append(2)                                                                                                                                                               

In [5]: a                                                                                                                                                                         
Out[5]: [2, 2]

In [6]: b                                                                                                                                                                         
Out[6]: [2, 2]

In [7]: b += [3, 4];                                                                                                                                                                        

In [8]: b
Out[8]: [2, 2, 3, 4]

In [9]: a
Out[9]: [2, 2, 3, 4]

Now what happened here? We changed b but a changed as well, this is because the append or update of the list happens in-place and since a was pointing to b both ends up getting updated!

What happens for += operator is defined by __iadd__ method of a class. For int-s all the __iXXX__ methods return a new instance of int. For list-s __iadd__(self, other) does self.extend(other); return self, so variable keeps pointing to same object.

As a result, even integers can be made to behave as a list, an example is here courtesy @imposeren

imposeren
  • 4,142
  • 1
  • 19
  • 27
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
  • Is the behavior the same for all mutable and immutable objects? For example, do tuples behave like ints and unlike lists? – Alec May 13 '19 at 04:28
  • Yes, the difference being you cannot operate on a tuple, like you operate on an integer by doing addition! – Devesh Kumar Singh May 13 '19 at 04:29
  • It's worth mentioning that any object can return whanever it wants for different operators, for example for `+=` it's determined by `obj_cls.__iadd__`. And it so happens that for `int`s a new object is returned. But it's possibly to define a custom "int-like" class with overloaded `__iadd__` method so that on `+=` current object will be changed and the same object returned. – imposeren May 13 '19 at 04:29
  • The explanation might sound great, but it is not correct. At first the id is not helpful here since the CPython interpreter used an optimization that maps small integers to the same object. Larger integers (>256) will behave differently. Also here it is not the point that the objects are mutable or not. What matter is how they are used and that they are assigned and not modified. – Klaus D. May 13 '19 at 04:35
  • Example code for my previous comment that shows how "int-like" objects can be made "mutable": https://gist.github.com/imposeren/5501a54a2ea0785cac57b104df9218c0 . @DeveshKumarSingh maybe you should mention this in your answer – imposeren May 13 '19 at 04:56
  • Hi @KlausD. , I have removed referenced of `id` from my example, and mentioned that integer modification makes a copy, whereas list modification happens inplace, hence the different behaviour! Please check the update! – Devesh Kumar Singh May 13 '19 at 05:02
  • Hi @imposeren, that's an interesting example, I have referred it in my answer, please check ! – Devesh Kumar Singh May 13 '19 at 05:04
  • The first part is much better now. The second part is, lets say, basically ok. – Klaus D. May 13 '19 at 05:09
  • You mean the first part referring to integer is better, but the one referring to list is not, what's missing there @KlausD. Could you explain please :) – Devesh Kumar Singh May 13 '19 at 05:12
  • @DeveshKumarSingh, made a minor edit to your answer explaining `a_list += [3, 4]`. Feel free to make extra edits – imposeren May 13 '19 at 05:13
  • Thanks @imposeren I am pretty new to python myself, and have learned by implementation, and still grasping the basics, so your explanation made sense to me and I learned more :) – Devesh Kumar Singh May 13 '19 at 05:17
2

In other programming languages, what you are talking about are called "pointers."
They have this name because they "point" to things.
a points to b, b points to 2, and so on.

I have drawn some pictures to describe what you thought would happen, and what actually happened.

What You Expected Would Happen:

enter image description here

What Actually Happened:

picture of actual behavior

Community
  • 1
  • 1
Toothpick Anemone
  • 4,290
  • 2
  • 20
  • 42
0

The variables in python are references. Few references are to immutable objects (such as strings, integers etc) whereas lists and sets are mutable.

Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 22:20:52) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
# Consider two variables x & y  with integers 23 and 46. They have immutable references
# Meaning, if y=x, it doesn't mean y will change whenever x is updated.
>>> x=23
>>> print (x)
23
>>> y=46
>>> print (x)
23
>>> print (y)
46
>>> y=x
>>> print (x)
23
>>> print (y)
23
# Let's change the value of x after the assignment
>>> x=99
>>> print (x)
99
# Since it is immutable, the value wont change.
>>> print (y)
23
#Let's consider the mutable reference scenario. a & b are two lists which have mutable references
# Meaning, if b=a, it means b will change whenever a is changed
>>> a = list([11,22,33,87])
>>> print (a)
[11, 22, 33, 87]
>>> b = list([87,53,98,2])
>>> print (b)
[87, 53, 98, 2]
>>> a=b
>>> print (a)
[87, 53, 98, 2]
>>> print (b)
[87, 53, 98, 2]
# Popping the list would alter b
>>> b.pop()
2
>>> print (b)
[87, 53, 98]
# Notice the change in value of a
>>> print (a)
[87, 53, 98]
>>>
hem
  • 1,012
  • 6
  • 11