自实例创建以来,我想验证类型是否正确,
我尝试使用@dataclass
装饰器,但不允许我使用__init__
方法,我还尝试使用自定义类类型
也按照类型的顺序进行了一些验证(例如,如果是int
,那个field>0
或如果是str
干净的空白),
我可以使用字典来验证类型,但是我想知道是否有一种方法可以用pythonic方式实现
class Car(object):
""" My class with many fields """
color: str
name: str
wheels: int
def __init__(self):
""" Get the type of fields and validate """
pass
答案 0 :(得分:1)
您可以使用数据类的__post_init__
方法进行验证。
下面我只确认所有内容都是指定类型的实例
from dataclasses import dataclass, fields
def validate(instance):
for field in fields(instance):
attr = getattr(instance, field.name)
if not isinstance(attr, field.type):
msg = "Field {0.name} is of type {1}, should be {0.type}".format(field, type(attr))
raise ValueError(msg)
@dataclass
class Car:
color: str
name: str
wheels: int
def __post_init__(self):
validate(self)
答案 1 :(得分:0)
@dataclass
的替代方法是使用pyfields
。它提供了开箱即用的验证和转换,并且直接在字段级别完成,因此您可以在任何类中使用field
,而无需进行任何修改。
from pyfields import field, init_fields
from valid8.validation_lib import is_in
ALLOWED_COLORS = ('blue', 'yellow', 'brown')
class Car(object):
""" My class with many fields """
color: str = field(check_type=True, validators=is_in(ALLOWED_COLORS))
name: str = field(check_type=True, validators={'should be non-empty': lambda s: len(s) > 0})
wheels: int = field(check_type=True, validators={'should be positive': lambda x: x > 0})
@init_fields
def __init__(self, msg="hello world!"):
print(msg)
c = Car(color='blue', name='roadie', wheels=3)
c.wheels = 'hello' # <-- (1) type validation error, see below
c.wheels = 0 # <-- (2) value validation error, see below
产生以下两个错误
TypeError: Invalid value type provided for '<...>.Car.wheels'.
Value should be of type <class 'int'>. Instead, received a 'str': 'hello'
和
valid8.entry_points.ValidationError[ValueError]:
Error validating [<...>.Car.wheels=0].
InvalidValue: should be positive.
Function [<lambda>] returned [False] for value 0.
有关详细信息,请参见pyfields
documentation。我是作者:)
答案 2 :(得分:0)
数据类不检查数据。但是我为数据类制作了一个小型的上层结构,您可以通过以下方式使用它:
import json
from dataclasses import dataclass
from validated_dc import ValidatedDC
@dataclass
class Car(ValidatedDC):
color: str
name: str
wheels: int
# This string was received by api
data = '{"color": "gray", "name": "Delorean", "wheels": 4}'
# Let's upload this json-string to the dictionary
data = json.loads(data)
car = Car(**data)
assert car.get_errors() is None
# Let's say the key "color" got the wrong value:
data['color'] = 11111
car = Car(**data)
assert car.get_errors()
print(car.get_errors())
# {
# 'color': [
# BasicValidationError(
# value_repr='11111', value_type=<class 'int'>,
# annotation=<class 'str'>, exception=None
# )
# ]
# }
# fix
car.color = 'gray'
# is_valid() - Starting validation of an already created instance
# (if True returns, then there are no errors)
assert car.is_valid()
assert car.get_errors() is None
ValidatedDC:https://github.com/EvgeniyBurdin/validated_dc
答案 3 :(得分:0)
使用pydantic。 在此示例中,字段 password1 仅被验证为字符串,而其他字段具有自定义验证器函数。
from pydantic import BaseModel, ValidationError, validator
class UserModel(BaseModel):
name: str
username: str
password1: str
password2: str
@validator('name')
def name_must_contain_space(cls, v):
if ' ' not in v:
raise ValueError('must contain a space')
return v.title()
@validator('password2')
def passwords_match(cls, v, values, **kwargs):
if 'password1' in values and v != values['password1']:
raise ValueError('passwords do not match')
return v
@validator('username')
def username_alphanumeric(cls, v):
assert v.isalnum(), 'must be alphanumeric'
return v
user = UserModel(
name='samuel colvin',
username='scolvin',
password1='zxcvbn',
password2='zxcvbn',
)
print(user)
#> name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn'
try:
UserModel(
name='samuel',
username='scolvin',
password1='zxcvbn',
password2='zxcvbn2',
)
except ValidationError as e:
print(e)
"""
2 validation errors for UserModel
name
must contain a space (type=value_error)
password2
passwords do not match (type=value_error)
"""