Python Dataclass验证:一种简单的方法?
我试图了解如何直接实现Python Dataclass验证。我正在使用棉花糖validate
尝试执行此操作,但不了解验证方式实际上可以在数据级别内运行,或者是否只是作为元数据字段而glomp在dataclast中,您必须尴尬地运行。
我可以做一个__ post_init __
(如建议在这里和在这里)直接执行验证在每个字段上,但我觉得应该有一种更容易的,验证的方法,可以根据其validate
元数据来验证所有字段,要么是__ Init __ Init __ 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
所以我可以做的是添加A __ 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.
但这似乎相当笨拙,似乎很难实现比这更复杂的验证。似乎我应该能够在参数传递时可以验证“前期”,而无需更改任何内容。
是否可以移动到完整的棉花糖dataclass
?可能将其视为架构
可以处理这一点。
I'm trying to understand how python dataclass validation can be implemented straightforwardly. I'm using marshmallow validate
to try to do this but not understanding how the validation can actually be run within the dataclass, or whether it is just glommed on as a metadata field that you have to rather awkwardly run.
I could do a __post_init__
(as suggested here and here) to directly perform the validation on each field but I feel like there should be an easier, validator-agnostic way to validate all the fields according to their validate
metadata, either at __init__
or otherwise.
Here is an example script below:
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)
I run this as follows but don't get any ValidationError
, so I know that the validation doesn't somehow happen magically inside the dataclass:
% python testing.py
this passes
this should fail
So what I can do is add a __post_init__
method like this to the dataclass:
def __post_init__(self):
for data_field in self.__dataclass_fields__:
self.__dataclass_fields__[data_field].metadata["validate"](
self.__dict__[data_field]
)
With this, the validation more or less works on an argument-wise basis:
% 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.
But this seems rather clunky, and it seems hard to implement more complex validations than this. It seems like I should be able to validate "up-front" when the argument is passed in, without changing anything.
Is the solution to move to a full marshmallow-dataclass
? Possibly treating as a Schema
could handle this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
事实证明,您可以使用棉花糖dataclasses及其
schema()
方法很容易地执行此操作。以下代码显示了没有
__ POST_INIT __
的所需行为,尽管我显然需要在棉花糖上进行更多阅读:当运行时,我会得到所需的结果:
It turns out that you can do this quite easily by using marshmallow dataclasses and their
Schema()
method.The below code shows the desired behavior without the
__post_init__
, though I clearly need to read up more on marshmallow:When it's run, I get the desired result: