3

Let's assume I execute the following:

>>> id(a)
139926795932424
>>> a
[1, 2, 3, 4]
>>> a = a + [5]
>>> id(a)

Will the last line of this script print 139926795932424? Or a new id will be assigned to a?

  • 9
    I would say the best way to find out is to try it yourself – Totem Jun 30 '17 at 23:06
  • 2
    What did the interpreter say when you hit Enter? (Did you mean to ask something that wouldn't be answered by just hitting Enter?) – user2357112 Jun 30 '17 at 23:06
  • 4
    It's a unique identifier for the object `a` refers to. It won't change for the lifetime of the object. In CPython `id(x)` returns the memory address of `x`. By doing `a + [5]` you create a new list and assign it back to the name `a`. It will create a new object and therefore a new id will be assigned. If you did `a.append(5)` instead then the id would have remained the same. Note that `a += [5]` is different in a sense that it will call `a.append(5)` in fact. – a_guest Jun 30 '17 at 23:07

4 Answers4

7

Will the last line of this script print 139926795932424? Or a new id will be assigned to a?

A new id will be assigned to a. Why? Because a refers to a different object.

a = a + [5] is syntactic sugar for a = a.__add__([5]), and since a.__add__([5]) returns a new object, a holds a reference to the new object rather than the old object. This can be observed with a simple example:

>>> a = [1, 2]
>>> b = a # copy the reference in a to b
>>> id(a) == id(b) # they match
True
>>> a = a + [5] # syntatic sugar for a = a.__add__([5])
>>> id(a) == id(b) # they no longer match
False
>>> 

Note that in that sense, a = a + [5] and a += [5] are not identical even though they produce the same result (a = [1, 2, 5]). The first example as said above, is syntactic sugar for a = a.__add__([5]). While the second is syntactic sugar for a = a.__iadd__([5]). The difference is that the latter method - __iadd__() - does not create a new object in memory. Rather, it modifies the existing list object, and returns a reference to it. Again like previously:

>>> a = [1, 2]
>>> b = a # copy the reference in a to b
>>> id(a) == id(b) # they match
True
>>> a += [5]
>>> id(a) == id(b) # they still match, `b` has mutated too!
True
>>> b
[1, 2, 5]
Christian Dean
  • 22,138
  • 7
  • 54
  • 87
  • 1
    Hey, thanks for the edit @Ev. Kounis. Those two cases are closely related, so it was a nice idea to edit to address both. I just clarified a few small things, and polished it up a bit. Just letting you know my thoughts on the matter. – Christian Dean Jul 19 '17 at 17:26
2

From the documentation:

id(object)

Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.

Since you assigned a new value to a, this new object will have another id.

See more details in this question.

Community
  • 1
  • 1
Aurélien Gasser
  • 3,043
  • 1
  • 20
  • 25
1
>>> a= [1,2,3]
>>> a
[1, 2, 3]
>>> id(a)
39384488
>>> a + [5]
[1, 2, 3, 5]
>>> id(a)
39384488

No the id() does not change as you are not creating a new instance or lifetime of the variable. See the documentation for id().

EDIT:

The above example does not reassign the variable like in the question. In that scenario it would be a new variable as a = a + [5] returns a new object.

Christian Dean
  • 22,138
  • 7
  • 54
  • 87
  • You missed to reassign the new list (`a + [5]`) to the name `a`. That's why your id doesn't change. For the scenario in the question it will change though. – a_guest Jun 30 '17 at 23:21
0

In Python, objects are given unique identification numbers that are “guaranteed to be unique and constant for the object during its lifetime.”

In your example, the line a = a + [5] is directly changing the list a and when we call the id() function on the list, we will see a different unique id number. This essentially creates a new list (new object!)

>>> a = [1, 2, 3, 4]
>>> id(a)
140250098481992

>>> a = a + [5]
>>> id(a)
140250098532296
Andrew Li
  • 55,805
  • 14
  • 125
  • 143
  • Thanks a_guest, i've revised my comment. Appreciate it! – Spencer Cheng Jun 30 '17 at 23:15
  • 2
    _"`a = a + [5]` is directly changing the list a [...]"_ - I think what you mean is that this **binds** `a` to a new object. The original list `a` referred to remains unchanged (although garbage collected probably). – a_guest Jun 30 '17 at 23:19
  • @mgilson While this is correct for the scenario in the question you linked it won't happen here. First the right hand side is evaluated which creates a new list in memory (`a + [5]`). By this moment the old this is still referred to by `a` (i.e. the reference count of this list did not reach zero yet). Only after that this new list is bound to `a` which reduces the reference count of the old list by one (and eventually makes it available to garbage collection). Imagine the right hand side cannot be evaluated (raises an exception) - e.g. `a + 5` - then `a` will still refer to the old list. – a_guest Jun 30 '17 at 23:35