Python案例怎么自定义校验规则?

wen python案例 74

本文目录导读:

Python案例怎么自定义校验规则?

  1. 使用装饰器实现校验
  2. 基于类的校验器
  3. 使用数据类(dataclass)实现
  4. 链式调用校验器
  5. 使用pydantic(最推荐的方式)
  6. 实际应用示例:表单验证器

在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())

推荐使用方式:

  1. 简单场景:使用装饰器或函数
  2. 复杂业务:使用类实现,支持链式调用
  3. 专业项目:使用 pydanticmarshmallow 等成熟的库
  4. 框架集成:使用框架自带的验证机制(如Django Forms、Flask-WTF)

选择哪种方式取决于你的具体需求和项目复杂度。

抱歉,评论功能暂时关闭!