本文目录导读:

我来详细介绍Python中参数校验的封装方法,包含多种实践方案。
基础装饰器方式
from functools import wraps
from typing import Any, Callable
def validate_args(**validators):
"""
参数校验装饰器
validators: 字段名 -> 校验函数 的映射
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
# 获取函数参数名
import inspect
sig = inspect.signature(func)
bound_args = sig.bind(*args, **kwargs)
bound_args.apply_defaults()
# 校验参数
for param_name, validator in validators.items():
if param_name in bound_args.arguments:
value = bound_args.arguments[param_name]
if not validator(value):
raise ValueError(
f"参数 '{param_name}' 校验失败,值为: {value}"
)
return func(*args, **kwargs)
return wrapper
return decorator
# 使用示例
def is_positive(value: Any) -> bool:
return isinstance(value, (int, float)) and value > 0
def is_string(value: Any) -> bool:
return isinstance(value, str) and len(value) > 0
@validate_args(
age=is_positive,
name=is_string
)
def create_user(name: str, age: int):
return f"User {name}, Age {age}"
# 测试
try:
print(create_user("Alice", 25)) # 正常
print(create_user("", -5)) # 报错
except ValueError as e:
print(f"错误: {e}")
dataclass + 验证器
from dataclasses import dataclass, field
from typing import Optional, List
from datetime import datetime
class ValidationError(Exception):
pass
@dataclass
class UserModel:
"""用户数据模型"""
username: str
email: str
age: int
phone: Optional[str] = None
created_at: datetime = field(default_factory=datetime.now)
def __post_init__(self):
self.validate()
def validate(self):
"""验证所有字段"""
errors = []
# 验证用户名
if not self.username or len(self.username) < 3:
errors.append("用户名至少3个字符")
if not self.username.isalnum():
errors.append("用户名只能包含字母和数字")
# 验证邮箱
if not self.email or '@' not in self.email:
errors.append("邮箱格式不正确")
# 验证年龄
if not isinstance(self.age, int) or self.age < 0 or self.age > 150:
errors.append("年龄必须在0-150之间")
# 验证手机号
if self.phone:
import re
if not re.match(r'^1[3-9]\d{9}$', self.phone):
errors.append("手机号格式不正确")
if errors:
raise ValidationError("; ".join(errors))
# 使用示例
try:
user = UserModel("alice", "alice@example.com", 25)
print(f"创建用户成功: {user}")
# 错误示例
bad_user = UserModel("ab", "invalid-email", -5)
except ValidationError as e:
print(f"验证失败: {e}")
Pydantic模型验证
from pydantic import BaseModel, validator, Field
from typing import Optional, List
from datetime import datetime
from enum import Enum
class UserRole(str, Enum):
ADMIN = "admin"
USER = "user"
GUEST = "guest"
class UserCreate(BaseModel):
"""用户创建请求模型"""
username: str = Field(..., min_length=3, max_length=50, description="用户名")
email: str = Field(..., description="邮箱地址")
age: int = Field(..., ge=0, le=150, description="年龄")
role: UserRole = Field(default=UserRole.USER, description="角色")
phone: Optional[str] = Field(None, description="手机号")
tags: List[str] = Field(default_factory=list, description="标签")
@validator('username')
def username_alphanumeric(cls, v):
if not v.isalnum():
raise ValueError('用户名只能包含字母和数字')
return v
@validator('email')
def email_valid(cls, v):
if '@' not in v:
raise ValueError('邮箱格式不正确')
return v
@validator('phone')
def phone_valid(cls, v):
if v is not None:
import re
if not re.match(r'^1[3-9]\d{9}$', v):
raise ValueError('手机号格式不正确')
return v
@validator('tags')
def tags_unique(cls, v):
if len(v) != len(set(v)):
raise ValueError('标签不能重复')
return v
class UserResponse(BaseModel):
"""用户响应模型"""
id: int
username: str
email: str
role: UserRole
created_at: datetime
class Config:
orm_mode = True
# 使用示例
try:
user_data = {
"username": "alice123",
"email": "alice@example.com",
"age": 25,
"tags": ["python", "developer"]
}
user = UserCreate(**user_data)
print(f"创建成功: {user.dict()}")
# 错误示例
bad_data = {
"username": "ab",
"email": "invalid",
"age": 200
}
bad_user = UserCreate(**bad_data)
except Exception as e:
print(f"验证失败: {e}")
链式校验器
from typing import Any, Callable, List, Tuple, Union
from functools import reduce
class ValidatorChain:
"""链式校验器"""
def __init__(self, value: Any, name: str = ""):
self.value = value
self.name = name
self.errors: List[str] = []
self._validators: List[Tuple[Callable, str]] = []
def required(self, message: str = None) -> 'ValidatorChain':
"""非空验证"""
def _required(v):
return v is not None and str(v).strip() != ""
msg = message or f"{self.name} 不能为空"
self._validators.append((_required, msg))
return self
def type_check(self, expected_type: type, message: str = None) -> 'ValidatorChain':
"""类型验证"""
def _type_check(v):
return isinstance(v, expected_type)
msg = message or f"{self.name} 必须是 {expected_type.__name__} 类型"
self._validators.append((_type_check, msg))
return self
def min_length(self, min_len: int, message: str = None) -> 'ValidatorChain':
"""最小长度验证"""
def _min_length(v):
return len(str(v)) >= min_len
msg = message or f"{self.name} 长度不能小于 {min_len}"
self._validators.append((_min_length, msg))
return self
def max_length(self, max_len: int, message: str = None) -> 'ValidatorChain':
"""最大长度验证"""
def _max_length(v):
return len(str(v)) <= max_len
msg = message or f"{self.name} 长度不能大于 {max_len}"
self._validators.append((_max_length, msg))
return self
def regex(self, pattern: str, message: str = None) -> 'ValidatorChain':
"""正则表达式验证"""
import re
def _regex(v):
return bool(re.match(pattern, str(v)))
msg = message or f"{self.name} 格式不正确"
self._validators.append((_regex, msg))
return self
def custom(self, validator: Callable, message: str) -> 'ValidatorChain':
"""自定义验证"""
self._validators.append((validator, message))
return self
def validate(self) -> Union[Any, None]:
"""执行验证"""
for validator, message in self._validators:
if not validator(self.value):
self.errors.append(message)
if self.errors:
raise ValueError("; ".join(self.errors))
return self.value
# 高级封装
class ValidatedField:
"""验证字段描述符"""
def __init__(self, validator_func: Callable):
self.validator_func = validator_func
self.name = ""
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj.__dict__.get(self.name)
def __set__(self, obj, value):
validated_value = self.validator_func(value, self.name)
obj.__dict__[self.name] = validated_value
class ValidatedUser:
"""使用验证字段的类"""
username = ValidatedField(
lambda v, n: ValidatorChain(v, n)
.required()
.type_check(str)
.min_length(3, "用户名至少3个字符")
.max_length(50, "用户名最多50个字符")
.custom(lambda x: x.isalnum(), "用户名只能包含字母和数字")
.validate()
)
age = ValidatedField(
lambda v, n: ValidatorChain(v, n)
.required()
.type_check(int)
.custom(lambda x: 0 <= x <= 150, "年龄必须在0-150之间")
.validate()
)
email = ValidatedField(
lambda v, n: ValidatorChain(v, n)
.required()
.type_check(str)
.regex(r'^[\w\.-]+@[\w\.-]+\.\w+$', "邮箱格式不正确")
.validate()
)
def __init__(self, username: str, age: int, email: str):
self.username = username
self.age = age
self.email = email
def __repr__(self):
return f"ValidatedUser(username='{self.username}', age={self.age}, email='{self.email}')"
# 使用示例
try:
user = ValidatedUser("alice123", 25, "alice@example.com")
print(f"创建成功: {user}")
# 错误示例
bad_user = ValidatedUser("ab", -5, "invalid")
except ValueError as e:
print(f"验证失败: {e}")
综合验证框架
from typing import Any, Dict, List, Optional, Callable
from dataclasses import dataclass, field
import re
from datetime import datetime
class ValidationRule:
"""验证规则基类"""
def validate(self, value: Any, field_name: str) -> None:
raise NotImplementedError
def get_message(self, field_name: str) -> str:
raise NotImplementedError
class Required(ValidationRule):
def validate(self, value: Any, field_name: str) -> None:
if value is None or str(value).strip() == "":
raise ValueError(f"{field_name} 不能为空")
class StringType(ValidationRule):
def validate(self, value: Any, field_name: str) -> None:
if not isinstance(value, str):
raise ValueError(f"{field_name} 必须是字符串类型")
class IntType(ValidationRule):
def validate(self, value: Any, field_name: str) -> None:
if not isinstance(value, int):
raise ValueError(f"{field_name} 必须是整数类型")
class MinLength(ValidationRule):
def __init__(self, min_len: int):
self.min_len = min_len
def validate(self, value: Any, field_name: str) -> None:
if len(str(value)) < self.min_len:
raise ValueError(f"{field_name} 长度不能小于 {self.min_len}")
class MaxLength(ValidationRule):
def __init__(self, max_len: int):
self.max_len = max_len
def validate(self, value: Any, field_name: str) -> None:
if len(str(value)) > self.max_len:
raise ValueError(f"{field_name} 长度不能大于 {self.max_len}")
class Regex(ValidationRule):
def __init__(self, pattern: str, message: str = None):
self.pattern = pattern
self.message = message
def validate(self, value: Any, field_name: str) -> None:
if not re.match(self.pattern, str(value)):
raise ValueError(self.message or f"{field_name} 格式不正确")
class Range(ValidationRule):
def __init__(self, min_val: Any = None, max_val: Any = None):
self.min_val = min_val
self.max_val = max_val
def validate(self, value: Any, field_name: str) -> None:
if self.min_val is not None and value < self.min_val:
raise ValueError(f"{field_name} 不能小于 {self.min_val}")
if self.max_val is not None and value > self.max_val:
raise ValueError(f"{field_name} 不能大于 {self.max_val}")
class FieldValidator:
"""字段验证器"""
def __init__(self, rules: List[ValidationRule]):
self.rules = rules
def validate(self, value: Any, field_name: str) -> None:
for rule in self.rules:
rule.validate(value, field_name)
class ModelValidator:
"""模型验证器"""
def __init__(self):
self._fields: Dict[str, FieldValidator] = {}
def add_field(self, name: str, rules: List[ValidationRule]) -> 'ModelValidator':
self._fields[name] = FieldValidator(rules)
return self
def validate(self, data: Dict[str, Any]) -> Dict[str, Any]:
errors = {}
for field_name, validator in self._fields.items():
value = data.get(field_name)
try:
validator.validate(value, field_name)
except ValueError as e:
errors[field_name] = str(e)
if errors:
raise ValidationError(errors)
return data
def create_validator(self) -> Callable:
"""创建可调用的验证器"""
def validator(data: Dict[str, Any]) -> Dict[str, Any]:
return self.validate(data)
return validator
# 使用示例
user_validator = ModelValidator()
user_validator.add_field("username", [
Required(),
StringType(),
MinLength(3),
MaxLength(50),
Regex(r'^\w+$', "用户名只能包含字母、数字和下划线")
])
user_validator.add_field("age", [
Required(),
IntType(),
Range(min_val=0, max_val=150)
])
user_validator.add_field("email", [
Required(),
StringType(),
Regex(r'^[\w\.-]+@[\w\.-]+\.\w+$', "邮箱格式不正确")
])
# 测试
test_data = {
"username": "alice_123",
"age": 25,
"email": "alice@example.com"
}
try:
validated_data = user_validator.validate(test_data)
print(f"验证通过: {validated_data}")
except ValidationError as e:
print(f"验证失败: {e.errors}")
性能优化版
from functools import lru_cache
from typing import Any, Dict, List, Callable
import time
class CachedValidator:
"""带缓存的验证器"""
def __init__(self):
self._validators: Dict[str, Callable] = {}
def add_rule(self, field: str, validator: Callable):
self._validators[field] = validator
@lru_cache(maxsize=1000)
def _validate_field(self, field: str, value_hash: int) -> bool:
"""缓存验证结果"""
if field not in self._validators:
return True
validator = self._validators[field]
# 从hash恢复实际值(示例简化)
return True
def validate(self, data: Dict[str, Any]) -> bool:
for field, value in data.items():
value_hash = hash(str(value))
if not self._validate_field(field, value_hash):
return False
return True
# 性能测试
class PerformanceTest:
def __init__(self):
self.validator = CachedValidator()
self.validator.add_rule("username", lambda x: len(x) >= 3)
self.validator.add_rule("age", lambda x: 0 <= x <= 150)
def test_performance(self, iterations: int = 10000):
test_data = {"username": "alice", "age": 25}
start = time.time()
for _ in range(iterations):
self.validator.validate(test_data)
end = time.time()
print(f"执行 {iterations} 次验证耗时: {end - start:.4f} 秒")
# 运行性能测试
if __name__ == "__main__":
perf_test = PerformanceTest()
perf_test.test_performance()
选择建议
- 简单项目: 使用装饰器方式(方案1)
- 数据处理类: 使用dataclass验证(方案2)
- API开发: 使用Pydantic(方案3)
- 复杂验证逻辑: 使用链式验证器(方案4)
- 框架开发: 使用综合验证框架(方案5)
- 高性能需求: 使用缓存验证器(方案6)
最佳实践
- 验证逻辑应集中管理
- 错误信息要清晰明确
- 考虑性能影响
- 支持自定义验证规则
- 保持验证器可测试性
这些方案可以根据项目的具体需求进行选择和组合。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播