16

The following makes sense to me:

>>> [] is []
False

Given that lists are mutable, I would expect [] to be a new empty list object every time it appears in an expression. Using this explanation however, the following surprises me:

id([]) == id([])
True

Why? What is the explanation?

Loax
  • 615
  • 5
  • 11
  • I would wager some nonzero sum of money that `id([]) == id([])` is not `True` on all flavors of python. (yep, checked.) cPython tends to reallocate memory in this way, it is an implementation detail. – roippi Feb 22 '14 at 02:19
  • @roippi I think it's actually a fluke of rapid malloc/free/malloc. `a = []; b = []; id(a) == id(b) # This is False` – Silas Ray Feb 22 '14 at 02:21
  • @roippi -- I would wager that there are some flavors of Python where it works sometimes and not others, depending on exactly when the GC runs. – Michael Lorton Feb 22 '14 at 02:21

1 Answers1

15

In the first example, [] is not [] precisely because the lists are mutable. If they weren't, they could safely map to the same one without issue.

In the second example, id([]) creates a list, gets the id, and deallocates the list. The second time around it creates a list again, but "puts it in the same place" because nothing much else has happened. id is only valid during an object's lifetime, and in this case its lifetime is virtually nil

From the docs on id:

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.


Commented disassembly:

   0 LOAD_GLOBAL              0 (id)    # load the id function
   3 BUILD_LIST               0         # create the first list
   6 CALL_FUNCTION            1         # get the id
   9 LOAD_GLOBAL              0 (id)    # load the id function
  12 BUILD_LIST               0         # create the second list
  15 CALL_FUNCTION            1         # get the id
  18 COMPARE_OP               2 (==)    # compare the two ids
  21 RETURN_VALUE                       # return the comparison

Note there is no STORE_FAST to retain the list. Therefore it was discarded immediately after getting passed to the id function.

mhlester
  • 22,781
  • 10
  • 52
  • 75
  • I remember you answered the same question not quite long before ;P – zhangxaochen Feb 22 '14 at 02:17
  • not this one, maybe it's not you, but must be a duplicate – zhangxaochen Feb 22 '14 at 02:22
  • 1
    Well answered. For example in `def f(x, y): return id(x) == id(y)` where both `x` and `y` have to stay alive, `f([], [])` evaluates to `False`. – Loax Feb 22 '14 at 02:29
  • Precisely. As long as their lifetimes overlap, they must by definition have unique keys. – mhlester Feb 22 '14 at 02:32
  • @mhlester Can you explain why two empty tuples declared independently e.g. `a = (), b = ()` have same id? disassembly shows STORE_FAST is called twice though. Just because tuples are immutable? – Aamir Rind Jun 13 '14 at 03:11
  • @Aamir, yes: because they are immutable, they will always store the same value. If the value is always the same, why store it twice? – mhlester Jun 13 '14 at 03:19