具有默认选项的数据类参数选择
Dataclass argument choices with a default option
我正在创建一个数据类,其中包含一个我希望只有几个可能值的字段。我在想这样的事情:
@dataclass
class Person:
name: str = field(default='Eric', choices=['Eric', 'John', 'Graham', 'Terry'])
我知道一种解决方案是验证 __post_init__
方法中的参数,但是是否有使用类似上述语法的更简洁的方法?
python 3.8引入了一个新的类型Literal
,可以在这里使用:
from dataclasses import dataclass
from typing import Literal
@dataclass
class Person:
name: Literal['Eric', 'John', 'Graham', 'Terry'] = 'Eric'
像 mypy
这样的类型检查器可以正确解释它,Person('John')
通过,而 Person('Marc')
被标记为不兼容。请注意,这种提示 需要 类型检查器才能发挥作用,当您只是 运行 代码时,它不会自行执行任何操作。
如果您使用的是旧 python 版本并且无法升级到 3.8,您还可以通过官方 pip-installable backport 包访问 Literal
类型 typing-extensions
,然后用 from typing_extensions import Literal
导入它。
如果您需要在运行时对传递的值进行实际检查,您应该考虑使用 pydantic
来定义您的数据类。它的主要目标是使用强大的验证引擎扩展类似数据类的结构,该引擎将检查类型提示以强制执行它们,即您考虑在 __post_init__
.
中手写的内容
适用于 Python 3.8 (typing.Literal):
from dataclasses import dataclass
from typing import Literal
from validated_dc import ValidatedDC
@dataclass
class Person(ValidatedDC):
name: Literal['Eric', 'John', 'Graham', 'Terry'] = 'Eric'
# Validation during instance creation
eric = Person()
assert eric.name == 'Eric'
assert eric.get_errors() is None
john = Person('John')
assert john.get_errors() is None
peter = Person('Peter') # <-- Invalid value!
assert peter.get_errors()
print(peter.get_errors())
# {'name': [
# LiteralValidationError(
# literal_repr='Peter', literal_type=<class 'str'>,
# annotation=typing.Literal['Eric', 'John', 'Graham', 'Terry']
# )
# ]}
# You can check at any time
assert john.is_valid() # Starts validation and returns True or False
john.name = 'Ivan' # <-- Invalid value!
assert not john.is_valid()
print(john.get_errors())
# {'name': [
# LiteralValidationError(
# literal_repr='Ivan', literal_type=<class 'str'>,
# annotation=typing.Literal['Eric', 'John', 'Graham', 'Terry']
# )
# ]}
john.name = 'John' # <-- Valid value
assert john.is_valid()
assert john.get_errors() is None
我正在创建一个数据类,其中包含一个我希望只有几个可能值的字段。我在想这样的事情:
@dataclass
class Person:
name: str = field(default='Eric', choices=['Eric', 'John', 'Graham', 'Terry'])
我知道一种解决方案是验证 __post_init__
方法中的参数,但是是否有使用类似上述语法的更简洁的方法?
python 3.8引入了一个新的类型Literal
,可以在这里使用:
from dataclasses import dataclass
from typing import Literal
@dataclass
class Person:
name: Literal['Eric', 'John', 'Graham', 'Terry'] = 'Eric'
像 mypy
这样的类型检查器可以正确解释它,Person('John')
通过,而 Person('Marc')
被标记为不兼容。请注意,这种提示 需要 类型检查器才能发挥作用,当您只是 运行 代码时,它不会自行执行任何操作。
如果您使用的是旧 python 版本并且无法升级到 3.8,您还可以通过官方 pip-installable backport 包访问 Literal
类型 typing-extensions
,然后用 from typing_extensions import Literal
导入它。
如果您需要在运行时对传递的值进行实际检查,您应该考虑使用 pydantic
来定义您的数据类。它的主要目标是使用强大的验证引擎扩展类似数据类的结构,该引擎将检查类型提示以强制执行它们,即您考虑在 __post_init__
.
适用于 Python 3.8 (typing.Literal):
from dataclasses import dataclass
from typing import Literal
from validated_dc import ValidatedDC
@dataclass
class Person(ValidatedDC):
name: Literal['Eric', 'John', 'Graham', 'Terry'] = 'Eric'
# Validation during instance creation
eric = Person()
assert eric.name == 'Eric'
assert eric.get_errors() is None
john = Person('John')
assert john.get_errors() is None
peter = Person('Peter') # <-- Invalid value!
assert peter.get_errors()
print(peter.get_errors())
# {'name': [
# LiteralValidationError(
# literal_repr='Peter', literal_type=<class 'str'>,
# annotation=typing.Literal['Eric', 'John', 'Graham', 'Terry']
# )
# ]}
# You can check at any time
assert john.is_valid() # Starts validation and returns True or False
john.name = 'Ivan' # <-- Invalid value!
assert not john.is_valid()
print(john.get_errors())
# {'name': [
# LiteralValidationError(
# literal_repr='Ivan', literal_type=<class 'str'>,
# annotation=typing.Literal['Eric', 'John', 'Graham', 'Terry']
# )
# ]}
john.name = 'John' # <-- Valid value
assert john.is_valid()
assert john.get_errors() is None