我正在创建一个数据类,其中有一个字段,我希望它只有几个可能的值。我考虑了以下代码:
@dataclass
class Person:
name: str = field(default='Eric', choices=['Eric', 'John', 'Graham', 'Terry'])
我知道一种解决方法是在__post_init__
方法中验证参数,但是否有更简洁的方式可以使用类似上面的语法来实现?
我正在创建一个数据类,其中有一个字段,我希望它只有几个可能的值。我考虑了以下代码:
@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后端包typing-extensions
访问Literal
类型,并使用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
enum
是否合适? - Patrick Haugh