joh*_*son 7 python python-dataclasses
我有以下非常简单的数据类:
import dataclasses
@dataclasses.dataclass
class Test:
value: int
Run Code Online (Sandbox Code Playgroud)
我创建了该类的实例,但我使用了一个字符串而不是整数:
>>> test = Test('1')
>>> type(test.value)
<class 'str'>
Run Code Online (Sandbox Code Playgroud)
我真正想要的是强制转换为我在类定义中定义的数据类型:
>>> test = Test('1')
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
我必须__init__手动编写该方法还是有一种简单的方法来实现此目的?
Mer*_*rig 15
您可以使用以下__post_init__方法来实现此目的:
import dataclasses
@dataclasses.dataclass
class Test:
value : int
def __post_init__(self):
self.value = int(self.value)
Run Code Online (Sandbox Code Playgroud)
该方法被调用如下__init__方法
https://docs.python.org/3/library/dataclasses.html#post-init-processing
从强制或检查类型的意义上讲,永远不要遵循dataclass属性的类型提示。大多数情况下,像mypy这样的静态类型检查器都可以完成这项工作,Python在运行时不会这样做,因为它永远不会这样做。
如果要添加手动类型检查代码,请使用以下__post_init__方法:
@dataclasses.dataclass
class Test:
value: int
def __post_init__(self):
if not isinstance(self.value, int):
raise ValueError('value not an int')
# or self.value = int(self.value)
Run Code Online (Sandbox Code Playgroud)
您可以dataclasses.fields(self)用来获取Field指定字段和类型的对象的元组,并在其上循环以针对每个字段自动执行此操作,而无需为每个字段单独编写。
def __post_init__(self):
for field in dataclasses.fields(self):
value = getattr(self, field.name)
if not isinstance(value, field.type):
raise ValueError(f'Expected {field.name} to be {field.type}, '
f'got {repr(value)}')
# or setattr(self, field.name, field.type(value))
Run Code Online (Sandbox Code Playgroud)
对于 Python dataclasses,替代方法是使用该__post_init__方法,如其他答案中指出的:
@dataclasses.dataclass
class Test:
value: int
def __post_init__(self):
self.value = int(self.value)
Run Code Online (Sandbox Code Playgroud)
>>> test = Test("42")
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
@attr.define
class Test:
value: int = attr.field(converter=int)
Run Code Online (Sandbox Code Playgroud)
>>> test = Test("42")
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
如果您的数据来自映射,您可以使用该包,它根据类和数据类cattrs中的类型注释进行转换:attr
@dataclasses.dataclass
class Test:
value: int
Run Code Online (Sandbox Code Playgroud)
>>> test = cattrs.structure({"value": "42"}, Test)
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
Pydantic将根据模型中字段的类型自动进行转换:
class Test(pydantic.BaseModel):
value: int
Run Code Online (Sandbox Code Playgroud)
>>> test = Test(value="42")
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
小智 5
使用pydantic.validate_arguments很容易实现
只需validate_arguments在您的数据类中使用装饰器:
from dataclasses import dataclass
from pydantic import validate_arguments
@validate_arguments
@dataclass
class Test:
value: int
Run Code Online (Sandbox Code Playgroud)
然后试试你的演示,'str type' 1 将从 转换str为int
>>> test = Test('1')
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
如果你传递了真正错误的类型,它会引发异常
>>> test = Test('apple')
Traceback (most recent call last):
...
pydantic.error_wrappers.ValidationError: 1 validation error for Test
value
value is not a valid integer (type=type_error.integer)
Run Code Online (Sandbox Code Playgroud)