Input validation is crucial for creating secure, reliable, and predictable Python functions. It helps prevent unexpected errors and potential security vulnerabilities.
Comprehensive Validation Strategies
Type Validation
Ensure inputs match expected data types.
def validate_type(value, expected_type):
if not isinstance(value, expected_type):
raise TypeError(f"Expected {expected_type}, got {type(value)}")
def process_user_data(name: str, age: int):
validate_type(name, str)
validate_type(age, int)
if len(name) < 2:
raise ValueError("Name too short")
if age < 0 or age > 120:
raise ValueError("Invalid age range")
return f"User: {name}, Age: {age}"
Validation Flow Diagram
graph TD
A[Input Received] --> B{Type Check}
B -->|Pass| C{Range Check}
B -->|Fail| D[Type Error]
C -->|Pass| E[Process Input]
C -->|Fail| F[Value Error]
Advanced Validation Techniques
Decorator-Based Validation
Create reusable input validation decorators.
def validate_input(type_spec, constraints=None):
def decorator(func):
def wrapper(*args, **kwargs):
## Type validation
for arg, expected_type in zip(args, type_spec):
if not isinstance(arg, expected_type):
raise TypeError(f"Expected {expected_type}, got {type(arg)}")
## Constraint validation
if constraints:
for constraint in constraints:
if not constraint(*args, **kwargs):
raise ValueError("Input fails validation constraints")
return func(*args, **kwargs)
return wrapper
return decorator
## Example usage
@validate_input(
[str, int],
[
lambda name, age: len(name) >= 2,
lambda name, age: 0 < age < 120
]
)
def create_user(name, age):
return f"User {name} created with age {age}"
## Valid calls
print(create_user("John", 30))
## These would raise exceptions
## create_user("A", 150)
## create_user(123, "invalid")
Validation Techniques Comparison
Validation Method |
Complexity |
Flexibility |
Performance |
Type Checking |
Low |
Medium |
High |
Decorator |
High |
High |
Medium |
Manual Validation |
Medium |
Very High |
Low |
Regular Expression Validation
import re
def validate_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(pattern, email):
raise ValueError("Invalid email format")
return email
def validate_phone(phone):
pattern = r'^\+?1?\d{10,14}$'
if not re.match(pattern, phone):
raise ValueError("Invalid phone number")
return phone
Preventing Injection and Security Risks
def sanitize_input(input_string):
## Remove potentially dangerous characters
return re.sub(r'[<>&\'"()]', '', input_string)
def safe_database_query(user_input):
cleaned_input = sanitize_input(user_input)
## Perform database query with sanitized input
Complex Validation Scenario
class InputValidator:
@staticmethod
def validate_complex_input(data):
validations = [
lambda x: isinstance(x, dict),
lambda x: all(isinstance(k, str) for k in x.keys()),
lambda x: 'name' in x and 'age' in x,
lambda x: isinstance(x['name'], str) and len(x['name']) > 1,
lambda x: isinstance(x['age'], int) and 0 < x['age'] < 120
]
return all(validation(data) for validation in validations)
## Usage
try:
valid_data = {"name": "Alice", "age": 30}
if InputValidator.validate_complex_input(valid_data):
print("Input is valid")
except Exception as e:
print(f"Validation failed: {e}")
LabEx Insight
Robust input validation is not just about preventing errors, but about creating resilient and secure code that gracefully handles unexpected inputs.