我试图了解python数据集验证是如何直接实现的。我正在使用棉花糖validate尝试这样做,但不了解验证是如何在数据块中实际运行的,或者它是否只是作为元数据字段(您必须相当笨拙地运行)。
我可以做一个__post_init__ (如建议的here和here)来直接对每个字段执行验证,但我觉得应该有一种简单、不可知的方法来根据所有字段的validate元数据(无论是在__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,因此我知道验证不会在dataclass中神奇地发生:
% python testing.py
this passes
this should fail因此,我可以做的是将这样的__post_init__方法添加到dataclass中:
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来处理这个问题。
发布于 2022-04-15 21:08:26
事实证明,通过使用棉花糖数据类型和它们的Schema()方法,您可以很容易地做到这一点。
下面的代码显示了在不使用__post_init__的情况下所需的行为,不过我显然需要阅读更多关于棉花糖的内容:
from dataclasses import dataclass, field
from marshmallow import validate, Schema
from marshmallow_dataclass import dataclass
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: NoneType = field(
default=None,
metadata=dict(
required=False,
validate=null_validate
)
)
print("this passes")
it = Testing.Schema().load({"plus_minus_one": 1, "max_one": 1, "null_field": None})
print("this should fail")
it = Testing.Schema().load({"plus_minus_one": 10, "max_one": 10, "null_field": 10})当它运行时,我得到了想要的结果:
this passes
this should fail
[...]
marshmallow.exceptions.ValidationError: {'null_field': ['Not a valid string.'], 'plus_minus_one': ['Must be one of: 1, -1.'], 'max_one': ['Must be less than or equal to 1.']}https://stackoverflow.com/questions/71888968
复制相似问题