本文目录导读:

在Python中自定义校验规则有多种方式,我来给你介绍几种常见的实现方法:
使用装饰器实现校验
def validate_positive(func):
def wrapper(value, *args, **kwargs):
if value <= 0:
raise ValueError(f"值 {value} 必须为正数")
return func(value, *args, **kwargs)
return wrapper
def validate_range(min_val, max_val):
def decorator(func):
def wrapper(value, *args, **kwargs):
if not (min_val <= value <= max_val):
raise ValueError(f"值 {value} 必须在 [{min_val}, {max_val}] 范围内")
return func(value, *args, **kwargs)
return wrapper
return decorator
@validate_positive
@validate_range(1, 100)
def process_age(age):
return f"年龄:{age}"
# 测试
try:
print(process_age(25)) # 正常
print(process_age(-5)) # 会报错
except ValueError as e:
print(f"错误:{e}")
基于类的校验器
class Validator:
def __init__(self):
self.rules = []
def add_rule(self, check_func, error_msg="校验失败"):
self.rules.append((check_func, error_msg))
def validate(self, value):
for check_func, error_msg in self.rules:
if not check_func(value):
raise ValueError(error_msg)
return True
# 创建校验器实例
email_validator = Validator()
email_validator.add_rule(lambda x: '@' in x, "必须包含@符号")
email_validator.add_rule(lambda x: len(x) > 5, "长度必须大于5")
email_validator.add_rule(lambda x: x.endswith('.com'), "必须以.com结尾")
# 使用校验器
def register_user(email):
email_validator.validate(email)
return f"用户注册成功:{email}"
# 测试
try:
print(register_user("test@example.com")) # 正常
print(register_user("invalid")) # 会报错
except ValueError as e:
print(f"错误:{e}")
使用数据类(dataclass)实现
from dataclasses import dataclass
from typing import Callable, List
@dataclass
class FieldValidator:
name: str
rules: List[Callable]
def validate(self, value):
for rule in self.rules:
rule(value)
class UserData:
def __init__(self):
self.validators = {
'username': FieldValidator('用户名', [
lambda x: len(x) >= 3 or self._raise_error("用户名至少3个字符"),
lambda x: x.isalnum() or self._raise_error("用户名只能包含字母和数字")
]),
'password': FieldValidator('密码', [
lambda x: len(x) >= 8 or self._raise_error("密码至少8位"),
lambda x: any(c.isupper() for c in x) or self._raise_error("密码需要包含大写字母"),
lambda x: any(c.isdigit() for c in x) or self._raise_error("密码需要包含数字")
])
}
def _raise_error(self, msg):
raise ValueError(msg)
def validate_user(self, username, password):
self.validators['username'].validate(username)
self.validators['password'].validate(password)
print("验证通过!")
# 使用示例
user = UserData()
try:
user.validate_user("test", "Hello123") # 正常
user.validate_user("ab", "弱密码") # 会报错
except ValueError as e:
print(f"验证错误:{e}")
链式调用校验器
class ValidatorChain:
def __init__(self):
self._checks = []
def add_rule(self, check_func, error_msg="校验失败"):
self._checks.append((check_func, error_msg))
return self # 返回self实现链式调用
def not_empty(self, error_msg="不能为空"):
return self.add_rule(lambda x: x is not None and x != "", error_msg)
def min_length(self, length, error_msg=None):
default_msg = f"长度不能小于{length}"
return self.add_rule(lambda x: len(str(x)) >= length, error_msg or default_msg)
def max_length(self, length, error_msg=None):
default_msg = f"长度不能大于{length}"
return self.add_rule(lambda x: len(str(x)) <= length, error_msg or default_msg)
def is_email(self, error_msg="不是有效的邮箱格式"):
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return self.add_rule(lambda x: re.match(pattern, x) is not None, error_msg)
def validate(self, value):
for check_func, error_msg in self._checks:
if not check_func(value):
raise ValueError(error_msg)
return True
# 使用示例
password_validator = ValidatorChain()
password_validator.not_empty("密码不能为空") \
.min_length(8, "密码至少8位") \
.max_length(20, "密码最多20位")
# 测试
try:
password_validator.validate("Hello@123")
print("密码验证通过")
password_validator.validate("short")
except ValueError as e:
print(f"验证失败:{e}")
使用pydantic(最推荐的方式)
# 需要先安装: pip install pydantic
from pydantic import BaseModel, validator, Field
from typing import Optional
class UserModel(BaseModel):
username: str = Field(..., min_length=3, max_length=50)
email: str
age: int = Field(..., ge=0, le=150)
password: str
@validator('email')
def validate_email(cls, v):
if '@' not in v:
raise ValueError('无效的邮箱格式')
return v
@validator('password')
def validate_password(cls, v):
if len(v) < 8:
raise ValueError('密码至少8位')
if not any(c.isupper() for c in v):
raise ValueError('密码需要包含大写字母')
if not any(c.isdigit() for c in v):
raise ValueError('密码需要包含数字')
return v
@validator('username')
def validate_username(cls, v):
if not v.isalnum():
raise ValueError('用户名只能包含字母和数字')
return v
# 使用示例
try:
user = UserModel(
username="张三",
email="zhangsan@example.com",
age=25,
password="Hello1234"
)
print(f"创建用户成功:{user.username}")
except Exception as e:
print(f"创建用户失败:{e}")
实际应用示例:表单验证器
class FormValidator:
"""表单验证器"""
def __init__(self):
self._fields = {}
self._errors = {}
def add_field(self, name, validators=None, required=True):
"""添加验证字段"""
self._fields[name] = {
'validators': validators or [],
'required': required
}
def validate(self, data):
"""验证所有字段"""
self._errors.clear()
for field_name, config in self._fields.items():
value = data.get(field_name)
# 检查必填字段
if config['required'] and (value is None or value == ''):
self._errors[field_name] = f"{field_name} 是必填字段"
continue
# 跳过空值非必填字段
if not config['required'] and (value is None or value == ''):
continue
# 执行校验规则
for validator in config['validators']:
try:
validator(value)
except ValueError as e:
self._errors[field_name] = str(e)
break
return len(self._errors) == 0
def get_errors(self):
"""获取错误信息"""
return self._errors
# 使用示例
def validate_age(age):
"""自定义年龄验证"""
if not isinstance(age, int) or age < 0 or age > 150:
raise ValueError("年龄必须在0-150之间")
def validate_phone(phone):
"""自定义电话号码验证"""
import re
if not re.match(r'^1[3-9]\d{9}$', phone):
raise ValueError("无效的手机号码格式")
# 创建表单验证器
form = FormValidator()
form.add_field('name', [lambda x: len(x) >= 2 or (_ for _ in ()).throw(ValueError("姓名至少2个字符"))])
form.add_field('age', [validate_age])
form.add_field('phone', [validate_phone])
form.add_field('email', [
lambda x: '@' in x or (_ for _ in ()).throw(ValueError("邮箱需要包含@")),
lambda x: '.' in x or (_ for _ in ()).throw(ValueError("邮箱需要包含. "))
])
# 测试验证
test_data = {
'name': '张三',
'age': 25,
'phone': '13800138000',
'email': 'test@example.com'
}
if form.validate(test_data):
print("所有字段验证通过!")
else:
print("验证失败:", form.get_errors())
推荐使用方式:
- 简单场景:使用装饰器或函数
- 复杂业务:使用类实现,支持链式调用
- 专业项目:使用
pydantic或marshmallow等成熟的库 - 框架集成:使用框架自带的验证机制(如Django Forms、Flask-WTF)
选择哪种方式取决于你的具体需求和项目复杂度。