2

Note that this question might be (is?) specific to CPython.

Say you have some list, and check copies of the list for identity against each other:

>>> a=list(range(10))
>>> b,c=a[:],a[:]
>>> b is c
False
>>> id(b), id(c)
(3157888272304, 3157888272256)

No great shakes there. But if we do this in a more ephemeral way, things might seem a bit weird at first:

>>> a[:] is a[:]
False  # <- two ephemeral copies not the same object (duh)
>>> id(a[:]),id(a[:])
(3157888272544, 3157888272544)   # <- but two other ephemerals share the same id..? hmm....

...until we recognize what is probably going on here. I have not confirmed it by looking at the CPython implementation (I can barely read c++ so it would be a waste of time, to be honest), but it at least seems obvious that even though two objects have the same id, CPython is smart enough to know that they aren't the same object.

Assuming this is correct, my question is: what criteria is CPython using to determine whether the two ephemeral objects are the not the same object, given that they have the same id (presumably for efficiency reasons- see below)? Is it perhaps looking at the time it was marked to be garbage collected? The time it was created? Or something else...?

My theory on why they have the same id is that, likely, CPython knows an ephemeral copy of the list was already made and is waiting to be garbage collected, and it just efficiently re-uses the same memory location. It would be great if an answer could clarify/confirm this as well.

Rick
  • 43,029
  • 15
  • 76
  • 119
  • You CANNOT ever compare two distinct ephemeral objects that happen to have the same id - the fact that you're comparing them implies that both exist at the same moment in time, which means that there's no opportunity for the second object to be allocated at the same address as the first. – jasonharper Jan 23 '19 at 17:14
  • 1
    The `list` objects you create to pass to `id` *cease to exist* after you pass them to `id`. Remember, CPython reference counting reclaims an object *as soon as the refcount goes to zero*. The CPython runtime has a privately managed heap that is very good about re-using memory. Python went ahead and re-used the same memory to allocate your new list object, passed to the second call of `id`. So, in other words, these two objects do not have overlapping lifetimes, therefore, there `id`'s arent guaranteed to be unique – juanpa.arrivillaga Jan 23 '19 at 17:15
  • @jasonharper Great. But my question is: how is CPython successfully determining that they are not the same object? – Rick Jan 23 '19 at 17:15
  • @RickTeachey you never compare them for object identity... where is CPython successfully determining they are not the same object? – juanpa.arrivillaga Jan 23 '19 at 17:16
  • @juanpa.arrivillaga Got it. But my question is: how is CPython getting a `False` here? It must be checking SOMETHING *other than the id* – Rick Jan 23 '19 at 17:16
  • @juanpa.arrivillaga this line: `>>> a[:] is a[:]` – Rick Jan 23 '19 at 17:17
  • @RickTeachey it *isn't*. It is checking the id. But if you use the `is` operator, they *wont have the same id at the time of checking* – juanpa.arrivillaga Jan 23 '19 at 17:17
  • 1
    In `a[:] is a[:]`, the two sides DON'T have the same id. – jasonharper Jan 23 '19 at 17:17
  • @jasonharper Yup, that's the answer; of course, side A and side B are in memory concurrently and GCed later. Yup, makes sense! – Rick Jan 23 '19 at 17:18
  • This question is not a duplicate because I'm asking something different than the proposed dup question. – Rick Jan 23 '19 at 17:19
  • @RickTeachey what are you asking and how isn't it answered by the duplicate? – juanpa.arrivillaga Jan 23 '19 at 17:19
  • @juanpa.arrivillaga I was not recognizing that the two objects exist simultaneously during the `is` operation. It's a different question because the other one was asking why the ids are the same; I was asking why the `is` operation succeeds. – Rick Jan 23 '19 at 17:20
  • 2
    I still maintain it is a valid duplicate, because your fundamental misunderstanding that the objects shared the same id during their lifetime. but feel free to vote to re-open. – juanpa.arrivillaga Jan 23 '19 at 17:22
  • 1
    Just because something is a duplicate doesn't mean it is a bad question. This one comes up in various forms from time to time. I added some other, more closely related duplicate targets – juanpa.arrivillaga Jan 23 '19 at 17:31

1 Answers1

3

Two unmutable objects, sharing the same address, would, as you are concerned, be indistinguishable from each other.

The thing is that when you do a[:] is a[:] both objetcts are not at the same address - in order for the identity operator is to compare both objects, both operands have to exist - so, there is still a reference to the object at the left hand side when the native code for is is actually run.

On the other hand, when you do id(a[:]),id(a[:]) the object inside the parentheses on the first call is left without any references as soon as the id function call is done, and is destroyed, freeing the memory block to be used by the second a[:].

jsbueno
  • 99,910
  • 10
  • 151
  • 209