4

This question is more a curiosity than anything else.

I've been reading the details of the implementation of the int object in Python (1 and 2) and, as far as I can see, a Python int is basically a C pointer to an struct, right?

So the question is basically, what happens in Python internally so equaling two ints in python doesn't point to the same instance while equaling complex types, such as list, does:

>>> a=5
>>> b=a
>>> print "id a: %s, id b: %s" % (id(a), id(b))
id a: 40802136, id b: 40802136
>>> b+=1
>>> print "a: %s, b: %s" % (a, b)
a: 5, b: 6
>>> print "id a: %s, id b: %s" % (id(a), id(b))
id a: 40802136, id b: 40802112

>>> a=[5]
>>> b=a
>>> print "id a: %s, id b: %s" % (id(a), id(b))
id a: 45930832, id b: 45930832
>>> b.append(1)
>>> print "a: %s, b: %s" % (a, b)
a: [5, 1], b: [5, 1]
>>> print "id a: %s, id b: %s" % (id(a), id(b))
id a: 45930832, id b: 45930832

My guess, by seeing the id of the instances above is because modifying an integer creates a new instance and re-assigns the new memory address to the variable. Is my suspicion correct? If so, does anyone know the "historical" decision of having ints behaving like this? Was it so programmers don't go nuts when int variables are assigned to other variables? (I'm totally ok with that, by the way :-D )

As I said, this is mainly a curiosity. Thank you in advance!

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
Savir
  • 17,568
  • 15
  • 82
  • 136
  • 5
    Calling the `.append()` method of an object is a completely different type of thing than re-binding the name with the `=` operator. It has absolutely nothing to do with the types of the objects, except in that the `int` has no methods that can mutate it. http://nedbatchelder.com/text/names.html is a good explanation of how names work in Python. – Wooble Apr 05 '14 at 16:20
  • 1
    I would have said `a += b` is like `a = a + b`, but it’s not. `+=` on a list does the same thing as `extend` in Python (which is silly). =/ – Ry- Apr 05 '14 at 16:22
  • Yeah, you guys are right. My example wasn't that good. I should've said what @minithech mentions – Savir Apr 05 '14 at 16:23
  • What do you mean by "equaling two ints in python doesn't point to the same instance"? Your own example shows that after {a=5; b=a}, id(a)==id(b)... – Jasper Apr 05 '14 at 16:24
  • @minitech; I think you mean `extend`. – DSM Apr 05 '14 at 16:32
  • 2
    @DSM: Yes, I do. Thanks =) [Hooray for time-unlimited moderator comment edits!] – Ry- Apr 05 '14 at 16:45
  • It may be worth taking a look at [PEP 203](http://legacy.python.org/dev/peps/pep-0203/) which describes the reasoning behind the augmented assignment operators being added to the language for Python 2.0. – Blckknght Apr 05 '14 at 19:17

1 Answers1

4

You are not modifying the original integer, you are creating a new one and assigning the variable to it, and so the id is different.

a = 5
b = a
b += 1             # created a new int
print id(a), id(b) # different

is the same as

a = 5
b = a
b = b + 1          # created a new int
print id(a), id(b) # different

The list equivalent would not be to use append, but to use +:

a = [5]
b = a
b = b + [6]        # created a new list
print id(a), id(b) # different

The is no equivalent append for ints, since ints cannot be modified but lists can.


The only potentially confusing thing is

a = [5]
b = a
b += [1]
print id(a), id(b) # same

The reason is that the += operator (unfortunately, IMO) modifies the original list, so b += [1] and b = b + [1] are not equivalent statements. (See Why does += behave unexpectedly on lists?)

Community
  • 1
  • 1
Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • You say it's unfortunate that `+=` is allowed to modify mutable objects in place, but that's the whole point of it! If `a` is a massive mutable object, `a += x` may be much faster than `a = a + x` if the latter requires creating a copy of `a`. – Blckknght Apr 05 '14 at 16:30
  • 2
    @Blckknght, true, but there is `extend` for that. To have `a += b` be different than `a = a + b` is a bit inconsistent. For `tuple`s, `int`s, and `float`s, the operators are equivalent, but `list`s they are not. – Paul Draper Apr 05 '14 at 16:34
  • If you were complaining about `+` being used to concatenate lists as well as `+=` being used to extend them, I think you'd have a point. But for any mutable type that supports `+`, `+=` should be available to do the same thin in place. For mutable numeric types like Numpy arrays, the operators are obviously correct, and you wouldn't want to have `+=` do a copy of a potentially very large data structure. – Blckknght Apr 05 '14 at 16:50
  • 1
    @Blckknght: Then I’d write `extend` instead of `+=`. Wouldn’t you expect `+=` to be equivalent to `= +` at first glance? Well, first glances are the most important ones. Explicit is better than implicit, etc.. Granted, it’s not often anyone would rely on it producing different lists, but it happens, and writing `l = l + [something]` would just look wrong. – Ry- Apr 05 '14 at 16:53
  • @minitech: I guess my first glances work differently than yours, and we may simply have to agree to disagree. I use mutable numeric types a lot so I'm pretty used to `+=` and its relatives (`-=`, `*=`, `/=`) doing in place operations. If there was no operator syntax for in-place operations, I'd be pretty unhappy! – Blckknght Apr 05 '14 at 17:14
  • @Blckknght, and I do believe that in-place operations being more common is the reason short symbols for them. I realize it makes for shorter code, but IMO it is still a surprising and unfortunate shortcut. Brevity vs. consistency ... not the first time they are at odds. – Paul Draper Apr 05 '14 at 17:17