2

id(A) == id(B) and A is B are regarded, as far as I understood, as tests for whether A and B refer to the same object. (see answers and comments Understanding Python's "is" operator)

But, applied to lists, we can get the following:

>>> id(['a', 'b', 'c']) == id(['a', 'b', 'c'])
True
>>> ['a', 'b', 'c'] is ['a', 'b', 'c']
False

Could someone explain what exactly happens 'behind the curtains' to enable such behavior?

Howz
  • 61
  • 4

1 Answers1

1

The id function returns a unique identifier for a live object. Two objects which are live at the same time cannot have the same id. Although, the doc also mentions that this does not apply for objects which are not alive at the same time.

Two objects with non-overlapping lifetimes may have the same id() value.

That is what happens in you case; when the second list is created the first one is no longer referenced and had been de-allocated.

We can observe this by disassembling your first example.

>>> import dis
>>> def f():
...     id([1, 2, 3]) == id([1, 2, 3])
... 
>>> dis.dis(f)
  2           0 LOAD_GLOBAL              0 (id)
              2 LOAD_CONST               1 (1)
              4 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              8 BUILD_LIST               3      # Creation of the first list
             10 CALL_FUNCTION            1      # After that point the first list is no longer referenced
             12 LOAD_GLOBAL              0 (id)
             14 LOAD_CONST               1 (1)
             16 LOAD_CONST               2 (2)
             18 LOAD_CONST               3 (3)
             20 BUILD_LIST               3      # Only here is the second list allocated
             22 CALL_FUNCTION            1
             24 COMPARE_OP               2 (==)
             26 POP_TOP
             28 LOAD_CONST               0 (None)
             30 RETURN_VALUE

Note that in the case of cPython, id returns the position of an object in memory. Thus, what you observe is simply Python reusing the same memory slot for two objects with disjoint lifespans. You can reproduce the example with lists which are not equal at all.

>>> id([1, 2, 3]) == id([4, 5, 6])
True
Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73
  • 1
    Thanks a lot for the detailed explanation! I was wondering that it should be linked to the lifetime of the objects but began doubting that it would happen within one "==" statement. Now it is clear. – Howz May 05 '20 at 22:12