Understanding and Avoiding 7 Common Code Smells in Python
Written on
Chapter 1: Introduction to Code Smells
In programming, issues don't always present themselves as outright failures; there are subtler signs that a problem may be looming. Much like noticing a gas leak or smoke in your home—these are signals that warrant immediate attention before they escalate into serious problems. In coding, a "code smell" acts similarly. It's an indication that something in your code could benefit from improvement, even if it isn't outright broken.
As defined, "Code smells are certain structures in the code that indicate violations of fundamental design principles, negatively impacting design quality." They are not outright bugs; instead, they represent design weaknesses that could hinder development or increase the likelihood of future errors. Recognizing and addressing these smells is crucial to maintaining healthy code and minimizing technical debt.
To effectively manage code quality, developers must be aware of these smells. In this article, we will explore seven prevalent code smells, starting with the first.
Section 1.1: Debugging with Print Statements
One of the earliest tools many programmers learn is the print statement. While it's a straightforward way to output information (most beginners start with print("Hello World")), over-reliance on print statements can signal a deeper issue.
If you find yourself using print statements primarily for debugging, it might be time to reconsider your approach. Although simple to implement, print debugging often leads to multiple iterations and can become cumbersome as you remove or edit these statements later.
Instead, consider using more efficient debugging methods:
- Employ a debugger to step through your code line by line.
- Utilize log files to record relevant information, allowing for easier comparison over multiple runs.
For instance, in Python, you can utilize the built-in logging module as follows:
import logging
logging.basicConfig(
filename="log_age.txt",
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.debug("This is a log message.")
The first video titled "7 Python Code Smells to AVOID at All Costs" delves deeper into this topic, offering insights into common pitfalls and how to navigate them.
Section 1.2: The Dangers of Duplicate Code
Duplicated code is a prevalent issue in many programs. It's easily identifiable: just look for sections where code has been copied and pasted. While it might seem harmless at first, the real danger surfaces during updates. Modifying one instance of duplicated code necessitates changes in all locations where it appears, and neglecting to do so can lead to hidden bugs.
To combat this issue, consider refactoring your code to eliminate duplicates. You can achieve this by utilizing functions or loops effectively:
def ask_meal(meal_of_the_day: str) -> str:
print(f"What would you like to eat for {meal_of_the_day}?")
meal = input()
return f"One {meal} coming up"
meals_of_the_day = ["breakfast", "lunch", "dinner"]
for meal in meals_of_the_day:
ask_meal(meal)
Chapter 2: More Code Smells to Avoid
The second video titled "More Python Code Smells: Avoid These 7 Smelly Snags" continues the discussion on additional code smells to watch out for.
Section 2.1: Understanding Magic Numbers
Magic numbers are specific values that appear in your code without explanation. They can lead to confusion for anyone reading or revisiting your code, obscuring your intent.
For example:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
0.3,
0.7,
25,
True,
None
)
To improve clarity, consider using constants:
TEST_SIZE = 0.3
TRAIN_SIZE = 0.7
RANDOM_STATE = 25
SHUFFLE = True
STRATIFY = None
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
TEST_SIZE,
TRAIN_SIZE,
RANDOM_STATE,
SHUFFLE,
STRATIFY
)
This makes your code significantly more readable.
Section 2.2: The Issue of Commented Out Code
While comments can be valuable, leaving commented-out code in place can create confusion. It’s often unclear why certain sections are commented and when they might be needed again.
If a piece of code is no longer relevant, it's best to remove it altogether.
Section 2.3: Eliminating Dead Code
Dead code refers to sections that are executed but not used, leading to wasted resources. It's essential to review your code and eliminate these sections to maintain efficiency.
Section 2.4: Avoiding Numeric Suffixes in Variables
Using numeric suffixes to distinguish similar variables can lead to confusion and poor readability. Instead, consider using lists or dictionaries to manage similar data more effectively:
people = ["John", "Doe", "Michael"]
Section 2.5: The Problem with Unnecessary Classes
In Python, it’s not mandatory to encapsulate code within classes as is common in languages like Java. If a class only contains a single method, it might be more efficient to simply use a function instead.
For further exploration of these concepts, check out Jack Diederich's PyCon 2012 talk on why we should "Stop Writing Classes."
Thank you for reading!
Connect with me:
Subscribe to stay updated on future publications.