Reputation: 177
id(t+t), id(t*2)
(42838592, 42838592)
(t+t) is (t*2)
False
If two variable point to same object 'is' operator will return true.But first line said both have same id but 'is' operator give false value.
Upvotes: 7
Views: 3843
Reputation: 365667
As explained by Ned Batchelder's answer, and by the docs for the id
function:
Two objects with non-overlapping lifetimes may have the same
id()
value.
And the two objects have non-overlapping lifetimes.
The fact that they're part of the same tuple expression doesn't change that, because it's not t+t
and t*2
that are part of a tuple, it's id(t+t)
and id(t*2)
. So, those two integer values returned by id
have an overlapping lifetime, but the arguments passed to id
do not.
One way to understand this is to look at how CPython compiles the code:
>>> dis.dis('id(t+t), id(t*2)')
1 0 LOAD_NAME 0 (id)
2 LOAD_NAME 1 (t)
4 LOAD_NAME 1 (t)
6 BINARY_ADD
8 CALL_FUNCTION 1
10 LOAD_NAME 0 (id)
12 LOAD_NAME 1 (t)
14 LOAD_CONST 0 (2)
16 BINARY_MULTIPLY
18 CALL_FUNCTION 1
20 BUILD_TUPLE 2
22 RETURN_VALUE
So, here's what happens. (I'm going to pick a value for t
, say 1000
, just to make this a bit easier to follow.)
id
, 1000
, and 1000
get pushed on the stack.BINARY_ADD
creates a 2000
value at location 42838592
.id
gets called on that value and returns a 42838592
value at location, say, 42838616
.42838592
value is no longer on the stack and wasn't stored anywhere, id
's parameter was the only reference to it, so when it gets decrefed at the end of the function, it's immediately deleted.id
, 1000
, and 2
get pushed on the stack.BINARY_MULTIPLY
creates a new 2000
object. Since location 42838592
was just returned to the object pool, the new value reuses that location.id
returns another 42838592
, this time at location, say, 42838640
.So, the two int
values 4283592
and 4283592
have overlapping lifetimes (and the first one overlaps with the second 2000
), the two 2000
s do not overlap.
And finally, notice that if t
is a small number,
>>> t = 2
>>> (t+t) is (t*2)
True
… because all 4
values (except in unusual cases) are references to the same object.
And meanwhile, if t
is a constant rather than a variable, 1000+1000 is 1000*2
may or may not be true, depending on your CPython version, because of the way constant folding within a compilation unit works.
All of which goes to show that trying to actually take advantage of whether two equal int
s are or are not the same object is pretty much always a terrible idea. The only reason you should ever care about this question is if you're trying to learn more about the internals of CPython.
And of course this is all CPython-specific. Most other Python interpreters use some form of garbage collector instead of refcounting, so the first 2000
is unlikely to be destroyed before the second one is created. Plus, not all of them use an object pool like CPython. Not to mention that they're allowed to do completely different things for id
as long as they can guarantee unique values for non-overlapping objects.
PyPy will actually usually return the same value here—but only because it folds t+t
and t*2
into the same object in the first place; try it with t+t
and t*3and you'll get completely different
id`s.
Upvotes: 7
Reputation: 375514
In the first example, your objects don't overlap in time: one is created then destroyed, then another is created with the same id.
When you compare them with is
, you are holding onto both objects, so they get different ids.
Upvotes: 11