【发布时间】:2022-10-04 19:56:32
【问题描述】:
我试图了解如何直接实现 python 数据类验证。我正在使用 marshmallow validate 尝试执行此操作,但不了解如何在数据类中实际运行验证,或者它是否只是作为一个元数据字段而您必须相当笨拙地运行。
我可以使用__post_init__(建议here 和here)直接对每个字段执行验证,但我觉得应该有一种更简单、与验证器无关的方法来根据@987654325 验证所有字段@ 元数据,在 __init__ 或其他位置。
下面是一个示例脚本:
from dataclasses import dataclass, field
from marshmallow import validate
def null_validate(value):
"""Validation fn for dataclass"""
if value is None:
pass
else:
raise ValidationError("{value} should be a string for this dataclass field!")
@dataclass
class Testing:
plus_minus_one: int = field(
default=None,
metadata=dict(
required=False,
validate=validate.OneOf([1, -1])
)
)
max_one: int = field(
default=None,
metadata=dict(
required=False,
validate=validate.Range(max=1)
)
)
null_field: str = field(
default=None,
metadata=dict(
required=False,
validate=null_validate
)
)
print("this passes")
it = Testing(1, 1, None)
print("this should fail")
it = Testing(10, 10, 10)
我按如下方式运行它,但没有得到任何ValidationError,所以我知道验证不会以某种方式在数据类中神奇地发生:
% python testing.py
this passes
this should fail
所以我能做的就是在数据类中添加一个像这样的__post_init__ 方法:
def __post_init__(self):
for data_field in self.__dataclass_fields__:
self.__dataclass_fields__[data_field].metadata["validate"](
self.__dict__[data_field]
)
有了这个,验证或多或少地在论证的基础上起作用:
% python testing.py
this passes
this should fail
Traceback (most recent call last):
File "testing.py", line 47, in <module>
it = Testing(10, 10, 10)
File "<string>", line 6, in __init__
File "testing.py", line 41, in __post_init__
self.__dataclass_fields__[data_field].metadata["validate"](self.__dict__[data_field])
File "/Users/max.press/miniconda3/envs/test_env/lib/python3.7/site-packages/marshmallow/validate.py", line 569, in __call__
raise ValidationError(self._format_error(value))
marshmallow.exceptions.ValidationError: Must be one of: 1, -1.
但这似乎相当笨拙,而且似乎很难实现比这更复杂的验证。似乎我应该能够在传入参数时“预先”验证,而无需更改任何内容。
移动到完整的marshmallow-dataclass 的解决方案是什么?可能将其视为Schema 可以处理此问题。
【问题讨论】:
标签: python validation python-dataclasses marshmallow