Easy performance optimizations in Python
Performance is probably not the first thing that pops up in your mind when you think about Python. Nor is it required in a typical I/O intensive application, where most CPU cycles are spent waiting. But if a few small fixes can give your program those tiny performance boosts, that doesn't hurt, right?
Here are three easy fixes which you can give your Python code that little extra speed that it deserves.
1. Using {} instead of dict to initialize a dictionary
When initializing a new dictionary, using {} is much more performant than calling the dict built-in.
To see why, let's look at the bytecode representation of both the statements.
dict is slower because it calls a function that essentially returns {}. Hence, any occurrences of dict() can be safely replaced with {}.
Take care, however, that you're not using {} (or even dict(), since it returns {}) in variables that will be passed around to a lot of functions. In such cases, you may want to pass the dict callable, and then execute the callable only inside the function.
2. Using is instead of == for singleton comparison
When comparing to a singleton object, like True, False and None, is should be preferred over ==. This is because is directly compares the IDs of the two objects, and a singleton object's ID never changes in a runtime.
However, == invokes the self.__eq__ method of the comparable. In the above example, the int class's __eq__ is invoked. Therefore, even though the time difference in the above example doesn't look like much, it is going to increase for instances of classes with a more complex __eq__ method.
3. Avoid unnecessary calls to len()
In order to check if a list has non-zero length in a condition, doing this is more performant:
As compared to doing this:
Or even:
Let us time both these variations using a slightly abridged snippet:
This is because bool(x) eventually ends up calling the equivalent of len(x), as there is no __bool__ method defined for list. To see why the second code is slower than the first, let's dig into the bytecode.
In the second case, there are 4 extra statements. The statement POP_JUMP_IF_FALSE returns the length of the list (if you dig deep into the CPython implementation). In the second case, however, the call to len precedes the condition checking. Hence, it ends up being slower than the first version.