Python Best PracticesΒΆ
This guide covers essential Python programming best practices for writing clean, efficient, and maintainable code following PEP 8 and Pythonic conventions.
π― Core Python Best PracticesΒΆ
Naming Conventions (PEP 8)ΒΆ
- Variables/Functions: snake_case (e.g.,
student_name,calculate_total()) - Classes: PascalCase (e.g.,
StudentRecord,DatabaseManager) - Constants: UPPER_SNAKE_CASE (e.g.,
MAX_RETRY_ATTEMPTS,DEFAULT_TIMEOUT) - Private Members: Leading underscore (e.g.,
_internal_method,__private_var) - Modules: lowercase with underscores (e.g.,
student_utils.py)
Code OrganizationΒΆ
- Docstrings: Use triple quotes for function/class documentation
- Type Hints: Add type annotations for better code clarity
- Import Organization: Group imports (standard library, third-party, local)
- Function Length: Keep functions short and focused on single responsibility
Pythonic IdiomsΒΆ
- List Comprehensions: Prefer over explicit loops
- Context Managers: Use
withfor resource management - Generators: Use
yieldfor memory-efficient iteration - Decorators: Use for cross-cutting concerns
π§ Python-Specific TechniquesΒΆ
Input/OutputΒΆ
# Good: Using context managers and exception handling
def get_user_input():
"""Get user input with proper error handling."""
try:
with open('data.txt', 'r') as file:
return file.read()
except FileNotFoundError:
print("File not found, using default value")
return "default"
except IOError as e:
print(f"Error reading file: {e}")
return None
# Bad: No error handling
def get_user_input_bad():
file = open('data.txt', 'r')
return file.read() # File never closed!
List OperationsΒΆ
# Good: List comprehensions and built-in functions
numbers = [1, 2, 3, 4, 5]
squares = [x**2 for x in numbers] # List comprehension
even_numbers = [x for x in numbers if x % 2 == 0] # Filtering
total = sum(numbers) # Built-in function
# Bad: Manual loops for simple operations
squares_bad = []
for x in numbers:
squares_bad.append(x**2)
total_bad = 0
for x in numbers:
total_bad += x
String HandlingΒΆ
# Good: f-strings and string methods
name = "John"
age = 25
message = f"My name is {name} and I'm {age} years old"
# Good: String methods for manipulation
text = " Hello World "
cleaned = text.strip().lower().replace(' ', '_')
# Bad: String concatenation with +
message_bad = "My name is " + name + " and I'm " + str(age) + " years old"
Function DesignΒΆ
# Good: Type hints, docstrings, single responsibility
from typing import List, Optional
def calculate_average(numbers: List[float]) -> Optional[float]:
"""
Calculate the average of a list of numbers.
Args:
numbers: List of numeric values
Returns:
Average value or None if list is empty
"""
if not numbers:
return None
return sum(numbers) / len(numbers)
# Bad: No type hints, unclear purpose
def calc(data):
# What does this function do?
return sum(data) / len(data)
β οΈ Common Python PitfallsΒΆ
Mutable Default ArgumentsΒΆ
# Bad: Mutable default argument
def add_item(item, items=[]): # Same list used across calls!
items.append(item)
return items
# Good: Use None as default
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
Variable Scope IssuesΒΆ
# Bad: Modifying loop variable
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
if numbers[i] % 2 == 0:
numbers.remove(i) # Modifying list while iterating!
# Good: Create new list or use list comprehension
numbers = [1, 2, 3, 4, 5]
even_numbers = [x for x in numbers if x % 2 == 0]
Comparison with NoneΒΆ
# Bad: Using == for None comparison
if value == None: # Should use 'is'
pass
# Good: Use 'is' for identity comparison
if value is None:
pass
# Better: Use truthiness for general cases
if not value:
pass
π Performance OptimizationΒΆ
Memory EfficiencyΒΆ
# Good: Generators for large datasets
def process_large_file(filename):
"""Process large file line by line."""
with open(filename, 'r') as file:
for line in file: # Generator, memory efficient
yield process_line(line)
# Bad: Loading entire file into memory
def process_large_file_bad(filename):
with open(filename, 'r') as file:
lines = file.readlines() # Loads entire file!
return [process_line(line) for line in lines]
Efficient Data StructuresΒΆ
# Good: Use appropriate data structures
# Set for membership testing (O(1))
valid_colors = {'red', 'green', 'blue'}
if color in valid_colors: # Fast lookup
pass
# Bad: List for membership testing (O(n))
valid_colors_bad = ['red', 'green', 'blue']
if color in valid_colors_bad: # Slow lookup
pass
String OperationsΒΆ
# Good: Join for string concatenation
words = ['hello', 'world', 'python']
sentence = ' '.join(words) # Efficient
# Bad: Repeated string concatenation
sentence_bad = ''
for word in words:
sentence_bad += word + ' ' # Creates new string each time
π οΈ Error HandlingΒΆ
Exception Handling Best PracticesΒΆ
# Good: Specific exceptions and proper cleanup
def read_config(filename):
"""Read configuration file with proper error handling."""
try:
with open(filename, 'r') as file:
return json.load(file)
except FileNotFoundError:
logging.error(f"Config file not found: {filename}")
return {}
except json.JSONDecodeError as e:
logging.error(f"Invalid JSON in config: {e}")
return {}
except Exception as e:
logging.error(f"Unexpected error reading config: {e}")
raise
# Bad: Catching all exceptions
def read_config_bad(filename):
try:
with open(filename, 'r') as file:
return json.load(file)
except: # Too broad!
return {}
π Testing Best PracticesΒΆ
Unit Testing with pytestΒΆ
# Good: Descriptive test names and assertions
import pytest
from calculator import add
def test_add_positive_numbers():
"""Test adding two positive numbers."""
result = add(2, 3)
assert result == 5
def test_add_negative_numbers():
"""Test adding two negative numbers."""
result = add(-2, -3)
assert result == -5
def test_add_with_none_raises_exception():
"""Test that add raises TypeError for None input."""
with pytest.raises(TypeError):
add(None, 5)
π¦ Project StructureΒΆ
Recommended Directory LayoutΒΆ
project_name/
βββ src/
β βββ project_name/
β βββ __init__.py
β βββ main.py
β βββ utils.py
βββ tests/
β βββ __init__.py
β βββ test_main.py
β βββ test_utils.py
βββ docs/
βββ requirements.txt
βββ setup.py
βββ README.md
Requirements ManagementΒΆ
π Related ResourcesΒΆ
- PEP 8 Style Guide - Official Python style guide
- Real Python - Comprehensive Python tutorials
- Python Documentation - Official Python docs
- Effective Python - Best practices book
π Related GuidesΒΆ
- Python Common Mistakes - Avoid frequent errors
- Python Performance Tips - Optimization techniques
- Python Testing Frameworks - Testing with pytest and unittest
- Python Resources - Learning materials and tools
π Common Programming Best PracticesΒΆ
- General Programming Principles - Universal concepts
- Code Organization - Structuring your code
- Debugging Strategies - Troubleshooting techniques