Python uses peephole optimization of your code by either pre-calculating constant expressions or transforming certain data structures.

This kind of optimization is really interesting because it’s something that happens underneath your code. You would normally not even know that all this stuff is happening.

Why is this done?

Constant Expressions

Optimizing constant expressions is really simple.

Suppose that you have the following multiplication,

What Python will do is pre-calculate that multiplication and will replace it for 86400. You might be wondering why not just write directly 86400 in the code, the answer is clarity.

The way the expression is written makes it pretty clear you are calculating the number of seconds in a a day: 60 seconds, times 60 minutes, times 24 hours. This is much clearer than 86400.

Python will pre-calculate the results and replace it where the (clear) multiplication was.

Short sequences also are pre-calculated.

Imagine you have this code,

myTuple = (2, 4)*5      # -> (2, 4, 2, 4, 2, 4, 2, 4, 2, 4)
myString = "qwerty "*2  # -> "qwerty qwerty "

This short sequences will be pre-calculated and Python will replace the original expression with the results (indicated in the comments).

Python has to balance between storage and computation. If it pre-calculates long sequences, the program might be faster but it will end up using more memory.

In order to see it, simply open a Python console and write the following code,

def my_func():
a = 60*60*24
myString = ("querty ") * 2
myTupple = (2, 4) *5
myString = ("This is a sequence with a lot of characters") * 100

Once this function is declared you can write the following code to access all the constants declared on the scope of that function,

my_func.__code__.co_consts

The output will look like,

>>> my_func.__code__.co_consts (None,
86400,
'querty querty ',
(2, 4, 2, 4, 2, 4, 2, 4, 2, 4),
'This is a sequence with a lot of characters',
100)

As you can see, in the output above Python has already pre-calculated the constant values and short sequences. Instead of having 60*60*24 the function already has the constant value 86400. The same thing happens with the tuple and the short string.

However, the long string multiplied by 100 didn’t get pre-calculated. That’s why you see two different constants, the string and the 100.

Membership Tests

What Python for membership tests is to transform mutable data structures to its inmutable version. Lists get transformed into tuples and sets into frozensets.

For instance,

def my_func(element):
if element in ["a", "b", "c"]:
print(element)

Is transformed to this,

def my_func(element):
if element in ("a", "b", "c"):
print(element)

Note that Python changes [] brackets to ().

This is done to access the immutable version of a data structure. This is faster than accessing the mutable one.

Check this by running the following code,

my_func.__code__.co_consts

The output will be the following,

>>> my_func.__code__.co_consts (None, ('a', 'b', 'c'))

The function has a constant value which is the inmutable version (a tuple) of the declared list.
Doing this as a set, you will see that it will be transformed into a frozenset,

def my_func(element):
if element in {"a", "b", "c"}:
print(element)
>>> my_func.__code__.co_consts (None, frozenset({'a', 'b', 'c'}))

Finally…

If you are interested on Python optimizations you could check out my article about Python Optimizations: Intering.