Perflint: Pylint Extension for Performance Anti-patterns
Perflint is an extension for Pylint that identifies performance anti-patterns in Python code, helping developers optimize their applications by flagging common inefficiencies. It is currently in early beta, version 0.8.1, and may produce false positives. The project is actively maintained with a focus on enhancing code performance through static analysis.
Common errors
-
pylint: error: no such option: --load-plugins=perflint
cause Perflint is not installed in the environment where Pylint is being run, or Pylint's version is too old to support plugin loading.fixEnsure `perflint` is installed in the same virtual environment as Pylint (`pip install perflint`). Also, ensure Pylint is up-to-date. -
W8101: unnecessary-list-cast
cause Using `list()` to cast an already iterable object (like a tuple or generator) into a list unnecessarily creates a new list object, which can be inefficient.fixRemove the `list()` constructor if the iterable type already suffices, e.g., `for item in my_tuple:` instead of `for item in list(my_tuple):`. -
W8102: incorrect-dictionary-iterator
cause Iterating over `dict.items()` and discarding either the key or the value (e.g., `for _, value in my_dict.items():`) is less efficient than using `dict.keys()` or `dict.values()` directly.fixUse `for value in my_dict.values():` if only values are needed, or `for key in my_dict.keys():` if only keys are needed.
Warnings
- gotcha Perflint is currently an 'early beta' and may generate false positives, requiring careful review of its findings.
- breaking Using `try...except` blocks inside loops can have significant computational overhead, especially in Python versions prior to 3.11 (R8203).
- gotcha Dotted imports (e.g., `os.path.exists`) inside loops can be inefficient because Python performs multiple lookups in each iteration (W8205).
- gotcha Accessing global variables within a tight loop can be slower than using local variables (W8202).
Install
-
pip install perflint
Imports
- Perflint as Pylint Plugin
from perflint import some_check
pylint your_module/ --load-plugins=perflint
Quickstart
import os
def process_data(items):
# W8202: Global name usage in a loop
# os.environ is a global lookup; cache it outside the loop for performance.
for item in items:
value = os.environ.get(item, 'default') # This will trigger W8202
print(value)
def unnecessary_list_cast_example(data):
# W8101: Unnecessary use of list() on an already iterable type
for x in list(data): # data is already iterable, no need for list()
print(x)
def incorrect_dict_iterator_example(dictionary):
# W8102: Incorrect iterator method for dict
for _, value in dictionary.items(): # If only values are needed, use .values()
print(value)
if __name__ == '__main__':
my_items = ['HOME', 'PATH']
process_data(my_items)
my_tuple = (1, 2, 3)
unnecessary_list_cast_example(my_tuple)
my_dict = {'a': 1, 'b': 2}
incorrect_dict_iterator_example(my_dict)