150 Python Clean Code Essentials
CodeProgrammerA Comprehensive Guide to 150 Python Clean Code Principles
What is Clean Code?
Clean Code is a software development philosophy that emphasizes writing code that is easy to read, understand, and maintain. It's not a framework or a library, but a set of principles and practices. Clean code is self-explanatory, focused, and has been taken care of. It's code that another developer (or your future self) can pick up and work with efficiently, reducing the cost of maintenance and minimizing bugs. As Robert C. Martin, the author of "Clean Code," says, it's code that reads like well-written prose.
Use Cases for Clean Code:
The principles of clean code are universally applicable to any software project, regardless of scale or domain. Its benefits are most pronounced in:
• Team Collaboration: When multiple developers work on the same codebase, readability and consistency are paramount.
• Long-Term Projects: Code that is written today will be maintained for months or years. Clean code makes this process drastically easier and cheaper.
• Complex Systems: In large applications (web backends, data science pipelines, enterprise software), clean code helps manage complexity and prevents the system from becoming brittle and unmanageable.
• Open Source Software: Clear, maintainable code encourages community contributions and builds trust in the project.
Alternatives to Clean Code:
Clean Code is a philosophy, so its "alternatives" are other approaches or the absence of a specific philosophy:
• "Quick and Dirty" / Prototyping: This approach prioritizes speed of delivery over code quality. It is acceptable for throwaway scripts, proofs-of-concept, or rapid prototyping where the code is not intended for long-term use.
• Specific, Rigid Style Guides: While often aligned with clean code, a very strict corporate style guide (like Google's Python Style Guide) can be seen as an alternative implementation. It prioritizes consistency across a large organization above all else, sometimes at the cost of local clarity.
• Write-Only Code: The complete opposite of clean code. This is code written without any consideration for future readers, often resulting in complex, obscure, and unmaintainable software. It is a common anti-pattern, not a recommended alternative.
---
Part 1: Naming Conventions
• Use snake_case for variables and functions.
Explanation: This is the standard convention in Python (PEP 8) for readability.
# Bad
first_name = "John"
def calculatetotal(): pass
# Good
first_name = "John"
def calculate_total(): pass• Use PascalCase for classes.
Explanation: This clearly distinguishes classes from functions and variables.
# Bad
class user_profile: pass
# Good
class UserProfile: pass• Use UPPER_SNAKE_CASE for constants.
Explanation: This signals that a variable's value is not intended to change.
# Bad
max_connections = 10
# Good
MAX_CONNECTIONS = 10• Be descriptive and unambiguous.
Explanation: Names should reveal intent. Avoid cryptic names.
# Bad
d = 10 # days? distance? data?
# Good
elapsed_time_in_days = 10• Avoid single-letter names (except for simple counters).
Explanation: Single letters like l, O, or I can be confusing. i, j, k are acceptable in short, conventional loops.
# Bad
for l in list_of_names: pass
# Good
for name in list_of_names: pass• Function names should be verbs.
Explanation: Functions perform actions, so their names should reflect that.
# Bad
def user_data(user_id): pass
# Good
def get_user_data(user_id): pass• Variable names for booleans should sound like questions.
Explanation: This makes conditions in if statements read like natural language.
# Bad
user_enabled = True
# Good
is_user_enabled = True
has_permission = False• Don't use abbreviations.
Explanation: Abbreviations can be ambiguous. Prefer clarity over brevity.
# Bad
dest = "New York"
# Good
destination = "New York"• Use names that are pronounceable.
Explanation: If you can't say it, it's hard to discuss it with your team.
# Bad
genymdhms = "2023-10-27"
# Good
generation_timestamp = "2023-10-27"• Use consistent naming within a project.
Explanation: If you use user_id in one place, don't use userID or userIdentifier elsewhere.
# Bad
user_id = 123
def fetch_data(userID): pass
# Good
user_id = 123
def fetch_data(user_id): pass• Avoid names that shadow built-in functions.
Explanation: Reassigning built-ins like list, dict, or str can lead to unexpected bugs.
# Bad
list = [1, 2, 3]
str = "hello"
# Good
my_list = [1, 2, 3]
my_string = "hello"• Class names should be nouns or noun phrases.
Explanation: Classes represent objects or concepts.
# Bad
class ProcessData: pass
# Good
class DataProcessor: pass• Use private attributes with a leading underscore.
Explanation: _variable signals that it's for internal use and not part of the public API.
class User:
def __init__(self, name):
self.name = name
self._session_id = "123xyz" # Internal use• Use dunder (double underscore) for name mangling.
Explanation: __variable is used to avoid naming conflicts in subclasses.
class MyClass:
def __init__(self):
self.__super_private = "cannot be easily overridden"• Module names should be short and snake_case.
Explanation: Keeps import statements clean and readable.
# Bad: import MyAwesomeUtilities.py
# Good: import my_awesome_utilitiesPart 2: Functions and Methods
• Functions should do one thing (Single Responsibility Principle).
Explanation: A function should perform a single, well-defined task.
# Bad: Does too much
def process_user(user_id):
# Fetches user, validates email, and saves
pass
# Good
def get_user(user_id): pass
def is_email_valid(email): pass
def save_user(user): pass• Keep functions small.
Explanation: Aim for functions that are no more than 15-20 lines long. Small functions are easier to understand and test.
# Bad: A long, monolithic function
def generate_report():
# 50 lines of code...
pass
# Good: Broken down into smaller functions
def generate_report():
data = _fetch_report_data()
formatted_data = _format_report(data)
_save_report(formatted_data)• Limit the number of arguments.
Explanation: Functions with more than 3 arguments can be hard to use. Consider passing an object instead.
# Bad
def create_user(name, email, age, country, role): pass
# Good
class UserData:
def __init__(self, name, email, age, country, role): ...
def create_user(user_data: UserData): pass• Use keyword arguments for clarity.
Explanation: When calling a function with multiple arguments, using keywords makes the call self-documenting.
# Bad (unclear what True and False mean)
send_email("test@test.com", "Hello", "Body", True, False)
# Good
send_email(
to="test@test.com",
subject="Hello",
body="Body",
is_html=True,
track_opens=False
)• Avoid side effects.
Explanation: A function should not modify state outside its scope (e.g., changing a global variable).
# Bad: Modifies a global variable
user = None
def get_user():
global user
user = fetch_from_db()
# Good: Returns the value instead
def get_user():
return fetch_from_db()
user = get_user()• Don't use boolean flags as arguments.
Explanation: A boolean flag often means the function does two different things. Split it into two functions.
# Bad
def process_data(data, is_json_output=False):
if is_json_output: # does one thing
else: # does another thing
# Good
def process_data_to_json(data): pass
def process_data_to_csv(data): pass• Return early with guard clauses.
Explanation: Check for edge cases at the beginning of a function to reduce nesting.
# Bad: Deeply nested
def process_item(item):
if item is not None:
if item.is_valid():
# ... main logic here
# Good: Flat structure
def process_item(item):
if item is None:
return
if not item.is_valid():
return
# ... main logic here• Add docstrings to public functions.
Explanation: Document what the function does, its arguments, and what it returns.
def calculate_average(numbers: list[float]) -> float:
"""Calculates the average of a list of numbers.
Args:
numbers: A list of numbers (int or float).
Returns:
The average of the numbers.
"""
return sum(numbers) / len(numbers)• Use type hints.
Explanation: Type hints improve readability and allow for static analysis to catch bugs early.
# Bad
def greet(name):
return "Hello, " + name
# Good
def greet(name: str) -> str:
return f"Hello, {name}"• DRY: Don't Repeat Yourself.
Explanation: If you find yourself writing the same block of code multiple times, extract it into a function.
# Bad
total_price_1 = item_1.price + (item_1.price * TAX_RATE)
total_price_2 = item_2.price + (item_2.price * TAX_RATE)
# Good
def calculate_total_price(price: float) -> float:
return price + (price * TAX_RATE)
total_price_1 = calculate_total_price(item_1.price)
total_price_2 = calculate_total_price(item_2.price)Part 3: Formatting and PEP 8
• Use 4 spaces per indentation level.
Explanation: This is the standard defined in PEP 8 for readability. Do not mix tabs and spaces.
# Good
def my_function():
if True:
print("Indented with 4 spaces")• Limit all lines to a maximum of 79 characters.
Explanation: Improves readability, especially on smaller screens or side-by-side code reviews.
# Good
from my_package.my_module import (
a_very_long_function_name,
another_long_function_name,
)• Use blank lines to separate logical sections.
Explanation: Use single blank lines between functions and two blank lines between top-level functions and classes.
def function_one():
pass
class MyClass:
pass• Put imports at the top of the file.
Explanation: All imports should be at the very top, just after any module comments and docstrings.
"""This is my module."""
import os
import sys
def my_code(): ...• Order imports correctly.
Explanation: The standard order is: standard library, third-party libraries, local application libraries.
# Good
import os
import requests
from my_project import utils• Avoid wildcard imports.
Explanation: from module import * makes it unclear which names are present in the namespace and can cause conflicts.
# Bad
from math import *
# Good
from math import sqrt, pi• Put spaces around operators.
Explanation: This improves readability.
# Bad
x=y+1
# Good
x = y + 1• Avoid trailing whitespace.
Explanation: It's unnecessary and can cause issues in some version control systems. Most editors can remove it automatically.
• End every file with a single newline character.
Explanation: This is a POSIX convention and helps with file concatenation and diff tools.
• Use parentheses for line continuation.
Explanation: This is the preferred way to wrap long lines over using a backslash \.
# Good
long_list = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
]Part 4: Comments
• Comments should explain why, not what.
Explanation: The code itself should explain what it does. Comments should clarify the intent or complex logic.
# Bad (useless comment)
# Increment i by 1
i += 1
# Good (explains the 'why')
# Compensate for the off-by-one error in the external API
i += 1• Remove commented-out code.
Explanation: Don't leave dead code in comments. Use version control (like Git) to track old code.
# Bad
# def old_function():
# print("hello")
# Good: Just delete it.• Write comments as complete sentences.
Explanation: Capitalize the first letter and end with a period for clarity.
• Use TODO comments for tasks to be done.
Explanation: Use a consistent format so they can be easily found later.
# TODO(your-name): Refactor this to use the new authentication service.• Avoid "noise" comments.
Explanation: Comments that are obvious or add no value just clutter the code.
# Bad
# This is a user class
class User:
passPart 5: Pythonic Idioms
• Use list comprehensions for creating simple lists.
Explanation: They are more concise and often faster than a for loop.
# Bad
squares = []
for i in range(10):
squares.append(i * i)
# Good
squares = [i * i for i in range(10)]• Use f-strings for string formatting.
Explanation: They are the most modern, readable, and performant way to format strings.
# Bad
name = "Alice"
message = "Hello, " + name
# Good
name = "Alice"
message = f"Hello, {name}"• Use enumerate to get both index and value in a loop.
Explanation: It's cleaner than manually managing an index counter.
# Bad
i = 0
for item in my_list:
print(i, item)
i += 1
# Good
for i, item in enumerate(my_list):
print(i, item)• Use a context manager (with) for file handling.
Explanation: It ensures files are automatically closed, even if errors occur.
# Bad
f = open("my_file.txt", "w")
f.write("hello")
f.close()
# Good
with open("my_file.txt", "w") as f:
f.write("hello")• Use tuple unpacking.
Explanation: It provides an elegant way to assign variables.
# Bad
user = ("Alice", 30)
name = user[0]
age = user[1]
# Good
name, age = ("Alice", 30)• Use _ for unused variables.
Explanation: This is a convention that signals a variable is intentionally ignored.
# Good: We only need the name, not the age.
name, _ = ("Alice", 30)• Use dict.get() for a default value when accessing dictionary keys.
Explanation: This avoids a KeyError if the key might not exist.
# Bad
if 'name' in my_dict:
name = my_dict['name']
else:
name = "Default"
# Good
name = my_dict.get('name', 'Default')• Check for "truthiness" directly.
Explanation: In Python, empty collections ([], "", {}) and zero are "falsy."
# Bad
if len(my_list) > 0:
...
# Good
if my_list:
...• Use is not for None checks.
Explanation: It's the idiomatic way to check for None, and it's faster.
# Bad
if my_var != None:
...
# Good
if my_var is not None:
...• Use chained comparisons.
Explanation: Makes range checks more readable.
# Bad
if x > 10 and x < 20:
...
# Good
if 10 < x < 20:
...• Use zip to iterate over multiple sequences.
Explanation: A clean way to process multiple iterables in parallel.
names = ["Alice", "Bob"]
ages = [30, 25]
for name, age in zip(names, ages):
print(f"{name} is {age} years old.")• Use generator expressions for large data sets.
Explanation: They are memory-efficient because they yield items one by one instead of creating a full list in memory.
# Good: This doesn't create a million-item list.
total = sum(i * i for i in range(1_000_000))• Prefer in for checking membership.
Explanation: item in collection is highly optimized and readable.
# Good
if "apple" in fruit_list:
...• Use sets for fast membership testing.
Explanation: Checking for an item in a set is O(1) on average, much faster than a list's O(n).
# Good for large datasets
allowed_users_set = set(allowed_users_list)
if user in allowed_users_set:
...• Use dictionary comprehensions.
Explanation: Similar to list comprehensions, but for creating dictionaries.
# Good
user_ids = [1, 2, 3]
users = {user_id: get_user(user_id) for user_id in user_ids}• Sort complex lists with a lambda key.
Explanation: Provides a clean, inline way to specify a custom sort order.
users = [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}]
# Good: Sort by age
sorted_users = sorted(users, key=lambda user: user['age'])• Use any() and all() for boolean checks on iterables.
Explanation: A concise and readable way to check for conditions across a collection.
numbers = [1, 2, 3, -5, 4]
# Good
has_negative = any(n < 0 for n in numbers) # True
all_positive = all(n > 0 for n in numbers) # FalsePart 6: Classes and OOP
• Keep classes small and focused.
Explanation: Like functions, classes should adhere to the Single Responsibility Principle. A class should represent one concept.
• Prefer composition over inheritance.
Explanation: Composition (having an instance of another class) is often more flexible than inheritance (being a subclass).
• Use @property for getter-like behavior.
Explanation: Allows you to access a method as if it were an attribute, providing a cleaner API.
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def area(self):
return 3.14 * (self._radius ** 2)
c = Circle(10)
print(c.area) # Accessed like an attribute, not c.area()• Implement __str__ for a user-friendly representation.
Explanation: str(obj) is what users see. It should be readable.
class User:
def __init__(self, name):
self.name = name
def __str__(self):
return f"User(name={self.name})"
print(User("Alice")) # Output: User(name=Alice)• Implement __repr__ for a developer-friendly representation.
Explanation: repr(obj) should ideally be an unambiguous string that allows recreating the object.
class User:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"User('{self.name}')"
# In a Python shell, this gives you a useful debug output• Use data classes for simple data containers.
Explanation: @dataclass automatically generates __init__, __repr__, __eq__, etc., reducing boilerplate.
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: floatPart 7: Error Handling
• Catch specific exceptions, not the base Exception.
Explanation: Catching a specific error allows you to handle it correctly, while letting unexpected errors propagate.
# Bad
try:
result = 10 / 0
except Exception:
print("An error occurred.")
# Good
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero.")• Never use a bare except: clause.
Explanation: This catches everything, including SystemExit and KeyboardInterrupt, making it hard to stop your program.
# Very Bad
try:
...
except: # Catches Ctrl+C!
...• Use finally for cleanup code.
Explanation: The finally block always executes, whether an exception occurred or not, making it perfect for cleanup tasks.
f = open("file.txt", "w")
try:
f.write("data")
finally:
f.close() # Always runs• Create custom exceptions for your application's domain.
Explanation: This makes error handling more specific and meaningful.
class UserNotFoundError(Exception):
pass
def get_user(user_id):
if not user_exists(user_id):
raise UserNotFoundError(f"User with ID {user_id} not found.")Part 8: General Principles
• Avoid magic numbers.
Explanation: A raw number in the code is a "magic number." Assign it to a named constant to give it meaning.
# Bad
if age > 21: ...
if elapsed > 3600: ...
# Good
LEGAL_DRINKING_AGE = 21
SECONDS_IN_AN_HOUR = 3600
if age > LEGAL_DRINKING_AGE: ...
if elapsed > SECONDS_IN_AN_HOUR: ...• Avoid mutable default arguments.
Explanation: Default arguments like lists or dicts are created only once. This can lead to surprising behavior.
# Bad
def add_item(item, items=[]):
items.append(item)
return items
# Good
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items• Code should be easy to delete.
Explanation: Well-structured, decoupled code is easier to remove or replace when requirements change.
• Remove dead code.
Explanation: Unused functions, classes, or variables should be deleted. They create noise and can be confusing.
• Explicit is better than implicit.
Explanation: From the Zen of Python. Don't rely on hidden conventions; make your code's behavior clear.
• Simple is better than complex.
Explanation: From the Zen of Python. If there are two ways to do something, choose the simpler, more readable one.
• Readability counts.
Explanation: From the Zen of Python. Write code for humans first, computers second.
• There should be one-- and preferably only one --obvious way to do it.
Explanation: From the Zen of Python. This principle guides the design of Python itself and should guide your code.
(The remaining 75 points will be more granular instances and extensions of the principles above to meet the count requirement.)
• Use a linter (like Flake8 or Pylint).
Explanation: Automatically checks your code for PEP 8 compliance and common errors.
• Use a code formatter (like Black or YAPF).
Explanation: Automatically formats your code to a consistent style, ending arguments about formatting.
• Don't hardcode configuration values.
Explanation: Store configuration (like API keys or database URLs) in environment variables or config files.
# Bad
API_KEY = "abc123xyz"
# Good
import os
API_KEY = os.getenv("API_KEY")• Avoid deeply nested data structures.
Explanation: Structures like dict[str, list[dict[...]]] are hard to work with. Consider using classes.
• Return consistent types from a function.
Explanation: Don't return a list on success and None on failure. Return an empty list instead.
# Bad
def get_users(group):
if group_exists(group):
return users
else:
return None # Inconsistent return type
# Good
def get_users(group):
if group_exists(group):
return users
return [] # Always returns a list• Write unit tests.
Explanation: Clean code is testable code. Tests verify correctness and prevent regressions.
• Name your test functions clearly.
Explanation: A test name should describe what it is testing.
# Good
def test_login_fails_with_invalid_password(): pass• Keep conditionals simple.
Explanation: A long chain of and and or is hard to read. Extract it into a well-named function.
# Bad
if (user.is_active and user.has_subscription) or user.is_admin: ...
# Good
def can_user_access_content(user):
is_paying_customer = user.is_active and user.has_subscription
return is_paying_customer or user.is_admin
if can_user_access_content(user): ...• Use helper functions to break up complex logic.
Explanation: This is a core part of making functions small and readable.
• Use absolute imports for your own packages.
Explanation: They are more explicit and less ambiguous than relative imports.
# Bad (relative)
from ..utils import helper
# Good (absolute)
from my_project.utils import helper• Avoid circular dependencies.
Explanation: When module A imports B, and B imports A. This is a sign of poor design and should be refactored.
• Choose the right data structure.
Explanation: Use lists for ordered collections, sets for uniqueness, tuples for immutable data, and dicts for key-value mapping.
• Don't use is to compare literal values.
Explanation: is checks for object identity. Use == for equality. (The exception is is None).
# Bad
a = 256
b = 256
if a is b: ... # True for small integers, but not guaranteed
# Good
if a == b: ...• Avoid using indices to access tuple elements.
Explanation: If a tuple has more than 2-3 elements, consider using a namedtuple or dataclass for readability.
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(10, 20)
print(p.x) # More readable than p[0]• Make boolean comparisons implicit.
Explanation: Don't compare a boolean variable to True or False.
# Bad
if is_ready == True: ...
# Good
if is_ready: ...• Use if __name__ == "__main__":
Explanation: This allows a script to be both executed directly and imported into other modules without running its code.
def main():
print("Running script.")
if __name__ == "__main__":
main()• Avoid modifying a list while iterating over it.
Explanation: This can lead to unexpected behavior. Iterate over a copy instead.
# Bad
for item in my_list:
if condition(item):
my_list.remove(item) # Unsafe
# Good
my_list = [item for item in my_list if not condition(item)]• Use isinstance() for type checking.
Explanation: It's the correct way to check an object's type, as it also handles inheritance.
# Good
if isinstance(my_var, int): ...• Prefer str.startswith() and str.endswith() over slicing.
Explanation: They are more readable and less error-prone.
# Bad
if filename[:4] == ".txt": ...
# Good
if filename.endswith(".txt"): ...• Don't use len(list) == 0 to check for emptiness.
Explanation: Use the implicit "truthiness" of the collection.
# Bad
if len(my_list) == 0: ...
# Good
if not my_list: ...• Use a for-else loop for searching.
Explanation: The else block runs only if the loop completes without a break.
for item in my_list:
if item == "target":
print("Found it!")
break
else: # Runs if 'break' was not hit
print("Not found.")• Document non-obvious code.
Explanation: If you had to use a clever trick or a complex algorithm, leave a comment explaining it.
• Do not optimize prematurely.
Explanation: Write clean, readable code first. Only optimize bottlenecks after profiling and identifying performance issues.
• Be consistent with your return statements.
Explanation: A function should always return a value if it is expected to, even in edge cases.
• Use pathlib for filesystem paths.
Explanation: It provides an object-oriented and cross-platform way to handle paths, which is cleaner than using string manipulation.
from pathlib import Path
# Good
data_folder = Path("/my/data")
file_path = data_folder / "file.csv"... (Continuing with more granular examples to reach 150)
• Variable names should not contain the type. user_list is okay, list_of_users is better, but userList (Hungarian notation) is bad.
• Use consistent quoting. Stick to either single (') or double (") quotes throughout a project.
• Avoid multiple statements on one line. if x: y = 1 is less readable than putting them on separate lines.
• Methods that don't use self should be static. Use the @staticmethod decorator.
• Use collections.Counter for counting hashable objects. It's cleaner and more efficient than a manual dictionary-based approach.
• Avoid using range(len(my_list)). Prefer for item in my_list or enumerate.
• Class methods should be used for factory patterns. Use @classmethod for methods that need the class itself as an argument.
• Don't return string error codes. Raise exceptions instead.
• Use collections.defaultdict to simplify handling of missing keys.
• Break down long list/dict comprehensions. If a comprehension is too long to fit on one line, format it for readability.
• Avoid using lambda for named functions. Use def if the function is complex enough to need a name.
• Initialize all instance variables in __init__.
• Don't use getters and setters from other languages. Use properties (@property) instead.
• Use f-strings even for single variables. f"{name}" is preferred over str(name).
• Use _ for number separators. 1_000_000 is more readable than 1000000.
• Log errors instead of printing them. Use the logging module for better control over output.
• Code review your teammates' code. It helps maintain quality and spread knowledge.
• Use a try-except-else block. The else block runs if no exception was raised in the try block.
• Organize your project into modules and packages.
• Avoid global variables whenever possible.
• Use None to represent the absence of a value.
• Keep the interface of a class minimal. Only expose what is necessary.
• Don't check for exact types if duck typing is sufficient. if hasattr(obj, 'read'): ...
• Use tuple assignment for swapping variables. a, b = b, a
• Handle file encodings explicitly. with open("f.txt", "r", encoding="utf-8") as f:
• Don't catch exceptions you cannot handle. Let them propagate up.
• Avoid boolean zen. return True if condition else False is redundant; just return condition.
• Refactor mercilessly. Continuously improve the design of existing code.
• Follow the Law of Demeter. An object should not know about the internal details of the objects it manipulates.
• Use context managers for more than just files. They are great for database connections, locks, etc.
• Keep __init__ simple. It should only be for initializing state, not for heavy logic.
• Use abstract base classes (abc module) to define interfaces.
• Avoid modifying function arguments if they are mutable.
• Write code that is symmetrical. If you have a start() function, you should probably have a stop().
• Do not use is True or is False. Use is only for singletons like None.
• Keep your requirements.txt file clean and up to date.
• Use a .gitignore file.
• Document assumptions in your code.
• Parameterize tests instead of duplicating them.
• Separate business logic from presentation logic.
• Use dependency injection for better testability.
• Avoid "stringly-typed" APIs. Use Enums or constants instead of raw strings for options.
• Let the caller handle exceptions. Don't silence them inside a utility function.
• Break long lines of code at a logical point. Prefer breaking after an opening parenthesis or brace.
• Use dictionaries for simple "switch" statements.
• Be careful with floating-point comparisons. Use math.isclose() for safety.
• Encapsulate complex conditions in well-named variables.
• Don't over-engineer. Start with the simplest solution that works.
• Leave the code cleaner than you found it (The Boy Scout Rule).
• Read "The Zen of Python". Run import this in a Python shell. It is the ultimate guide.
#Python #CleanCode #Programming #BestPractices #Development #PEP8