Cleaning Your Code: Refactoring Python Code Smells for Professional Design
Overview
Code that works isn't necessarily good code. In software development, a
Prerequisites
To follow this tutorial, you should have a solid grasp of
Key Libraries & Tools
- enum: A built-inPythonlibrary used to create sets of symbolic names bound to unique, constant values.
- abc: The Abstract Base Classes module, essential for defining blueprints for subclasses.
- PEP 8: The official style guide forPythoncode that ensures readability.
Code Walkthrough
1. Replacing Strings with Enums
Using strings for categories like roles (e.g., "manager") is risky. A typo causes a silent failure. Instead, use an
from enum import Enum, auto
class Role(Enum):
PRESIDENT = auto()
VICE_PRESIDENT = auto()
MANAGER = auto()
2. Eliminating Type-Checking with Polymorphism
Using isinstance() to branch logic is a major red flag. It couples your main logic to every single subclass. The fix? Move the logic into the class itself.
from abc import ABC, abstractmethod
class Employee(ABC):
@abstractmethod
def pay(self) -> None:
pass
class HourlyEmployee(Employee):
def pay(self) -> None:
print("Paying hourly rate.")
By calling employee.pay(), the if/else chains.
3. Splitting Multi-Purpose Methods
Methods that use a
# Smelly: def take_holiday(self, payout: bool)
# Clean:
def take_holiday(self):
# Logic for taking one day off
def payout_holiday(self):
# Logic for cashing out vacation days
4. Custom Exceptions for Better Context
Don't just raise ValueError. It doesn't tell the caller why the value is wrong. Create a custom exception that carries data.
class VacationShortageError(Exception):
def __init__(self, requested, remaining):
self.requested = requested
self.remaining = remaining
super().__init__(f"Tried to take {requested} days, but only {remaining} left.")
Syntax Notes
- list comprehension: These provide a concise way to create lists. They replace a multi-line
forloop andappend()call with a single, readable line. - abc: By inheriting from
ABCand using@abstractmethod, you prevent the base class from being instantiated, ensuring all subclasses implement the required interface.
Practical Examples
These refactorings are standard in
Tips & Gotchas
- Never swallow exceptions: An empty
except: passblock is a silent killer. It can hide syntax errors or even prevent you from stopping the program withCtrl+C. - Be Descriptive: A variable named
amountis useless.hours_workedorhourly_rate_usdprovides instant context without needing a comment. - DRY (Don't Repeat Yourself): If you see the same three lines of code in four different methods, it's time to extract them into a single, generic function.
