Python has a “recommended way of writing” called “Pythonic,” which leverages features and conventions unique to Python. Bringing habits from other programming languages or continuing to write verbose code is called an “Anti-pattern,” which causes poor readability and maintainability.
This article introduces common anti-patterns and compares them with improved code examples to help you write more efficient Python.
1. Use Chained Comparison Operators
When determining if a number falls within a specific range, there is no need to connect expressions using and.
Anti-pattern:
age = 25
# Common in other languages, but verbose in Python
if 18 <= age and age < 60:
print("Working age")
Improved: You can chain comparison operators just like in mathematical inequalities.
age = 25
# Intuitive and readable
if 18 <= age < 60:
print("Working age")
2. Use in for Checking Against Multiple Values
When checking if a variable matches any of several candidates, chaining with or is inefficient.
Anti-pattern:
role = "editor"
if role == "admin" or role == "editor" or role == "moderator":
print("Access granted to admin panel")
Improved: You can summarize conditions concisely using a tuple or set with the in operator.
role = "editor"
# Group candidates in a tuple
if role in ("admin", "editor", "moderator"):
print("Access granted to admin panel")
3. Truth Value Testing
When checking boolean values or whether a list is empty/non-empty, you do not need to write == True or len() > 0.
Anti-pattern:
is_valid = True
user_list = ["user1"]
if is_valid == True:
print("Valid")
if len(user_list) > 0:
print("User exists")
Improved: In Python, if you write a variable directly in a conditional expression, it is automatically evaluated as a truth value (recommended by PEP 8).
- True:
True, non-zero numbers, non-empty containers - False:
False,None,0, empty containers ([],"",{})
is_valid = True
user_list = ["user1"]
if is_valid:
print("Valid")
if user_list:
print("User exists")
4. Utilizing Ternary Operators (Conditional Expressions)
When assigning a value to a variable based on a simple condition, expanding it into an if-else block makes the code vertically long.
Anti-pattern:
score = 85
result = ""
if score >= 80:
result = "Pass"
else:
result = "Fail"
Improved: By using a conditional expression (ternary operator), you can write it in one line.
score = 85
result = "Pass" if score >= 80 else "Fail"
5. No Counter Variable Needed for Sequence Loops
Generating an index (counter) using len() and range() to access list elements is not recommended in Python.
Anti-pattern:
fruits = ["Apple", "Banana", "Cherry"]
# C-style access using index
for i in range(len(fruits)):
print(fruits[i])
Improved: Passing the list directly to the for statement extracts elements in order from the beginning.
fruits = ["Apple", "Banana", "Cherry"]
# Extract elements directly
for fruit in fruits:
print(fruit)
6. Assign Simultaneously if Values are the Same
When initializing multiple variables with the same initial value, there is no need to split lines.
Anti-pattern:
x = 0
y = 0
z = 0
Improved: You can initialize at once by chaining =.
x = y = z = 0
7. Utilizing List Comprehensions
When creating a new list from an existing list, creating an empty list and repeating append is verbose and slightly slower.
Anti-pattern:
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for n in numbers:
squared_numbers.append(n ** 2)
Improved: Using list comprehension allows for concise and fast writing.
numbers = [1, 2, 3, 4, 5]
squared_numbers = [n ** 2 for n in numbers]
8. Beware of Overwriting Global Names (Shadowing)
If you use built-in function names like list, str, sum, or id as variable names, the original functionality becomes unavailable (Shadowing).
Anti-pattern:
# Should avoid the variable name 'list'
list = [10, 20, 30]
# The original list() function becomes unusable and causes an error
# new_list = list((1, 2))
# TypeError: 'list' object is not callable
Improved: Use meaningful variable names or names that do not conflict with type names.
number_list = [10, 20, 30]
# Original function remains available
new_list = list((1, 2))
9. No Temporary Variable Needed for Swapping
You do not need to prepare a temporary variable (temp) to swap values between variables.
Anti-pattern:
a = 100
b = 200
temp = a
a = b
b = temp
Improved: Using Python’s tuple unpacking allows for a smart swap in one line.
a = 100
b = 200
a, b = b, a
Summary
Adopting these writing styles not only shortens the code but also clarifies intent and reduces bugs.
- Chain comparisons.
- Group multiple candidates with
in. - Keep truth value testing simple.
- Loop directly over iterables.
- Use comprehensions and unpacking.
- Do not use built-in function names as variable names.
Keep these in mind and aim for Pythonic code.
