API Rate Limiting
- Rate limiting ensures you don’t overwhelm an API.
- Use tools like
time.sleep()to limit the frequency of API requests.
__enter__ and __exit__ for Context Management
- Custom context managers can be created using
__enter__and__exit__. - Use
withto ensure proper setup and teardown.
Timing Blocks for Performance Analysis
- Use
timeortimeitto measure the performance of code blocks.
SQLAlchemy for Database Operations
- SQLAlchemy provides an ORM for interacting with databases, and
pyodbcis used for database connections. - Use
create_engineto establish a database connection. - Connection Pooling: Helps manage connections efficiently.
- Query Building: SQLAlchemy allows complex queries to be built using ORM or the SQL Expression Language.
Using pandas.read_sql() for SQL Queries
pandas.read_sql()allows you to run SQL queries directly and load the results into a DataFrame.
Dependency Injection: Avoid hardcoding dependencies by passing them into functions or classes.
class FileProcessor:
def __init__(self, file_reader):
self.file_reader = file_reader
class FileReader:
def read(self):
pass
Facade Pattern: Simplifies complex system interfaces by providing a higher-level interface.
class FileHandler:
def process_file(self, filepath):
# Complex operations
pass
class FileFacade:
def __init__(self):
self.file_handler = FileHandler()
def handle_file(self, filepath):
self.file_handler.process_file(filepath)
The facade FileFacade is necessary because in this class, you can consolidate various way to process a file, making codes neat and dry.
decorator factory is a pattern where you create a function that returns a decorator. It’s useful when your decorator needs parameters — like a custom logger.
for example
# Function that we will decorate with our timer_decorator
@timer_decorator
def slow_function():
print("Starting a slow function...")
time.sleep(2) # Simulate a slow operation (e.g., sleep for 2 seconds)
print("Slow function finished.")
# Call the decorated function
slow_function()
This syntax is equivalent to slow_function = timer_decorator(slow_function). note the full function of decorator timer_decorator is
import time
# Decorator to measure the execution time of a function
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time() # Record start time
result = func(*args, **kwargs) # Call the original function
end_time = time.time() # Record end time
execution_time = end_time - start_time # Calculate execution time
print(f"Function {func.__name__} executed in {execution_time:.4f} seconds")
return result # Return the result of the original function
return wrapper
Another great example involves three layers:
def log_execution_time(logger):
def decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
logger.info(f"{func.__name__} took {end_time - start_time:.3f} seconds to complete")
return result
return wrapper
return decorator
All of them are useful! If I remove the outer layer, removing the outer layer limits flexibility and means the decorator cannot accept external parameters (like a logger).