The Python "is" statement and tuples

Go To


Why is () is () true, yet (0,) is (0,) is false?

I thought they would be the same object. However, I'm apparently missing something.

2012-04-04 04:34
by rectangletangle
is means that they're the same object in memory. Apparently CPython only has one copy of the empty tuple but makes new ones for tuples with contents - Dougal 2012-04-04 04:36
Seems like they could use the same location in memory for identical tuples, seeing as they're immutable. However, there's probably a reason why they don't - rectangletangle 2012-04-04 04:44
@RectangleTangle, you would need an efficient way to locate the identical tuple. Think about how you would do tha - John La Rooy 2012-04-04 04:53
Interning tuples is technically possible, but the implementation is more complicated than interning strings since tuples can hold mutable types - Matt Eckert 2012-04-04 04:57


is tests to see if both sides of the statement share the same memory address. It's basically a shorthand for id(a) == id(b)

>>> print id(()), id(())
30085168 30085168
>>> print id((0,)), id((0,))
38560624 38676432

As () happens fairly frequently, it is actually treated as a singleton by the Python Interpreter (just like integers from 0 to 255, empty strings, empty lists, etc.). When comparing (0, ) to (0, ) to the interpreter they are actually different variables in memory. If they were mutable, you could modify the first, and the second wouldn't change, hence they are not the same (a is not b).

2012-04-04 04:52
by Esteban Küber
Empty lists aren't singletons; they're mutable, so you want each occurrence of [] to create a new list! Also, be careful with using id on temporary objects like that; on my system entering (id([]), id([])) into the REPL gives (48511432L, 48511432L), but this doesn't mean they were the same object; it's just that the first list was discarded as garbage after being ided, then the second was allocated into this convenient empty-list-sized hole in memory that just freed up. id values are potentially meaningless unless you ensure that the object lives longer than the id value - Ben 2012-04-04 06:17
@Ben, assigning the lists to names (that would last through the comparison) would eliminate that potential problem, right - rectangletangle 2012-04-04 07:00
@RectangleTangle Exactly right - Ben 2012-04-04 07:09
@Ben Does the expression [] is [] suffer from the same temporary object issue (i.e., can it evaluate as True simply because memory was reused)? I am guessing not, but not sure how this is prevented - max 2012-04-23 06:25
@max Correct, is testing is fine. The reason is that is tests the objects directly, which means they must both be alive at the same time in order for you to pass them to is, so there's no way they can accidentally have the same memory address if they're different objects. Comparing id results separates things out into multiple stages, creating the possibility that the first object is deallocated after you take its id but before the second object is allocated, which creates the possibility that two different objects get allocated at the same address and have the same id - Ben 2012-04-23 21:25


is tests for identity, not equality. That means Python simply compares the memory address a object resides in. is basically answers the question "Do I have two names for the same object?"

Usually Python writes each tuple into a different memory location,
interning will mostly happens only for string literals.

2012-04-04 04:45
by shahjapan


As Dougal says in his comment, is tests that the two things you are comparing are the in the same place in memory. For things like numbers, strings, booleans and the empty tuple, Python reuses objects by default (interning) so is will often produce the same behaviour as ==. This also means that you can get some performance gains by comparing memory pointers rather than more complex datatypes like strings.

For other things such as the tuple in your case (even though they are immutable), or lists and even the empty list [], Python will create a new object in a different memory location and is won't work the same way as ==

If you're trying to compare the two tuples by value, == would be the better comparison.

2012-04-04 05:04
by chees
It's fairly easy to get Python to create multiple versions of strings and numbers that are equal. Python doesn't promise to intern them, it just may choose to do so to save memory, so the behaviour of is becomes unpredictable for these objects. So while using is to compare strings can be more efficient, it runs the risk of introducing subtle bugs to your code unless you use it only in controlled places where you know the behaviour of your program can't run into this issue. Generally immutable objects should always be compared with == rather than is - Ben 2012-04-04 06:05
@Ben, wouldn't a is b or a == b also work? Though, the second comparison may negate the performance gained - rectangletangle 2012-04-04 06:18
@RectangleTangle Depends; if a usually isn't b, then you're just wasting work most of the time. Using multiple Python-level operations to save a short C loop also doesn't sound that likely to be a huge payoff, unless comparing huge a string to itself is common. I just use == when what I'm testing is semantically equality and is when what I'm testing is semantically identity. In theory I could then go back and replace some of these if I found string comparison to be a significant bottleneck in a program that was too slow, but this has never happened to me - Ben 2012-04-04 06:23
@Ben you're right, i should qualify my statement about getting performance gains - you can only really rely on it for booleans, None, and the empty tuple. For strings and numbers the behaviour can be ill-defined - chees 2012-04-04 06:25
i shouldn't have mentioned the performance gain at all actually: it might tempt people to prematurely optimise. we should always start with the clearest semantics, as per ben's practise - chees 2012-04-04 06:29