Which approach is better? Using a tuple, like:
if number in (1, 2):
or a list, like:
if number in [1, 2]:
Which one is recommended for such uses and why (both logical and performance wise)?
Which approach is better? Using a tuple, like:
if number in (1, 2):
or a list, like:
if number in [1, 2]:
Which one is recommended for such uses and why (both logical and performance wise)?
The CPython interpreter replaces the second form with the first.
That's because loading the tuple from a constant is one operation, but the list would be 3 operations; load the two integer contents and build a new list object.
Because you are using a list literal that isn't otherwise reachable, it is substituted for a tuple:
Here the second bytecode loads a
(1, 2)
tuple as a constant, in one step. Compare this to creating a list object not used in a membership test:Here N+1 steps are required for a list object of length N.
This substitution is a CPython-specific peephole optimisation; see the
Python/peephole.c
source. For other Python implementations then, you want to stick with immutable objects instead.That said, the best option when using Python 3.2 and up, is to use a set literal:
as the peephole optimiser will replace that with a
frozenset()
object and membership tests against sets are O(1) constant operations:This optimization was added in Python 3.2 but wasn't backported to Python 2.
As such, the Python 2 optimiser doesn't recognize this option and the cost of building either a
set
orfrozenset
from the contents is almost guaranteed to be more costly than using a tuple for the test.Set membership tests are O(1) and fast; testing against a tuple is O(n) worst case. Although testing agains a set has to calculate the hash (higher constant cost, cached for immutable tupes), the cost for testing against a tuple other than the first element is always going to be higher. So on average, sets are easily faster: