Python 3.7如何验证输入属性

时间:2018-08-08 00:00:25

标签: python-3.x oop python-3.7

自实例创建以来,我想验证类型是否正确, 我尝试使用@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

4 个答案:

答案 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)
    """