具有默认选项的Dataclass参数选择

6

我正在创建一个数据类,其中有一个字段,我希望它只有几个可能的值。我考虑了以下代码:

@dataclass
class Person:
   name: str = field(default='Eric', choices=['Eric', 'John', 'Graham', 'Terry'])

我知道一种解决方法是在__post_init__方法中验证参数,但是否有更简洁的方式可以使用类似上面的语法来实现?


对于您的使用情况,使用一个enum是否合适? - Patrick Haugh
2个回答

12

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__ 中手动编写的内容。


1
请注意,这不会进行任何运行时验证,只有静态代码检查器才能捕获错误。 - deceze
@deceze 好观点,我添加了一些更多的信息,以使区别更清晰。 - Arne

2

适用于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

已验证的数据中心:https://github.com/EvgeniyBurdin/validated_dc


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接