具有默认选项的数据类参数选项



我正在创建一个数据类,其中包含一个字段,我希望它只有几个可能的值。我在想这样的事情:

@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可安装向后移植包typing-extensions访问Literal类型,并使用from typing_extensions import Literal将其导入。


如果需要在运行时对传递的值进行实际检查,则应考虑改用pydantic来定义数据类。它的主要目标是使用强大的验证引擎扩展类似数据类的结构,该引擎将检查类型提示以强制执行它们,即您认为在__post_init__中手写的内容。

适用于 Python 3.8(键入。字面意思(:

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

已验证DC:https://github.com/EvgeniyBurdin/validated_dc

最新更新