Python Tips and Tricks for Efficient Coding
Python is known for its simplicity and readability, but there are many advanced techniques that can make your code even more efficient and elegant. Here are some essential tips and tricks every Python developer should know.
List Comprehensions
Replace loops with concise list comprehensions:
# Traditional approach
squares = []
for i in range(10):
squares.append(i**2)
# List comprehension
squares = [i**2 for i in range(10)]
# With condition
even_squares = [i**2 for i in range(10) if i % 2 == 0]
# Nested comprehensions
matrix = [[i*j for j in range(3)] for i in range(3)]
Dictionary and Set Comprehensions
Create dictionaries and sets efficiently:
# Dictionary comprehension
word_lengths = {word: len(word) for word in ['hello', 'world', 'python']}
# Set comprehension
unique_lengths = {len(word) for word in ['hello', 'world', 'python']}
# Conditional dictionary comprehension
positive_nums = {k: v for k, v in numbers.items() if v > 0}
Enumerate and Zip
Work with indices and multiple iterables:
# Enumerate for index and value
fruits = ['apple', 'banana', 'orange']
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# Zip for parallel iteration
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
# Zip with different lengths
from itertools import zip_longest
for name, age in zip_longest(names, ages, fillvalue='Unknown'):
print(f"{name}: {age}")
Context Managers
Handle resources properly with context managers:
# File handling
with open('file.txt', 'r') as f:
content = f.read()
# File automatically closed
# Custom context manager
from contextlib import contextmanager
@contextmanager
def timer():
import time
start = time.time()
try:
yield
finally:
end = time.time()
print(f"Execution time: {end - start:.2f} seconds")
# Usage
with timer():
# Your code here
time.sleep(1)
Decorators
Enhance functions with decorators:
# Simple decorator
def timing_decorator(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.2f} seconds")
return result
return wrapper
@timing_decorator
def slow_function():
time.sleep(1)
return "Done"
# Decorator with parameters
def retry(max_attempts=3):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise e
print(f"Attempt {attempt + 1} failed: {e}")
return wrapper
return decorator
@retry(max_attempts=3)
def unreliable_function():
import random
if random.random() < 0.7:
raise Exception("Random failure")
return "Success"
Generator Functions
Create memory-efficient iterators:
# Generator function
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# Usage
for num in fibonacci(10):
print(num)
# Generator expression
squares_gen = (x**2 for x in range(1000000)) # Memory efficient
# Reading large files
def read_large_file(file_path):
with open(file_path, 'r') as f:
for line in f:
yield line.strip()
Lambda Functions and Functional Programming
Use lambda functions and functional programming concepts:
# Lambda functions
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
# Reduce
from functools import reduce
product = reduce(lambda x, y: x * y, numbers)
# Partial functions
from functools import partial
def multiply(x, y):
return x * y
double = partial(multiply, 2)
print(double(5)) # 10
String Formatting
Modern string formatting techniques:
name = "Alice"
age = 30
score = 95.567
# f-strings (Python 3.6+)
message = f"Hello {name}, you are {age} years old"
formatted_score = f"Score: {score:.2f}"
# Format with expressions
result = f"Next year you'll be {age + 1}"
# Format with format specifiers
binary = f"Binary: {42:b}"
hex_val = f"Hex: {42:x}"
percentage = f"Percentage: {0.95:.1%}"
Collections Module
Use specialized data structures:
from collections import Counter, defaultdict, namedtuple, deque
# Counter
text = "hello world"
char_count = Counter(text)
print(char_count.most_common(3))
# defaultdict
dd = defaultdict(list)
dd['key'].append('value') # No KeyError
# namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x, p.y)
# deque for efficient append/pop operations
dq = deque([1, 2, 3])
dq.appendleft(0) # Efficient left append
dq.popleft() # Efficient left pop
Error Handling Best Practices
Handle errors gracefully:
# Specific exception handling
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Cannot divide by zero: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
else:
print("No errors occurred")
finally:
print("This always executes")
# EAFP (Easier to Ask for Forgiveness than Permission)
try:
value = dictionary['key']
except KeyError:
value = 'default'
# Better than LBYL (Look Before You Leap)
if 'key' in dictionary:
value = dictionary['key']
else:
value = 'default'
Conclusion
These Python tips and tricks will help you write more efficient, readable, and Pythonic code. Practice incorporating them into your projects to become a more effective Python developer.
Remember: "Simple is better than complex" - The Zen of Python
Happy coding! 🐍