Search code examples
pythonpython-3.xfieldpython-3.7python-dataclasses

Dataclass argument choices with a default option


I'm making a dataclass with a field for which I'd like there to only be a few possible values. I was thinking something like this:

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

I know that one solution is to validate arguments in the __post_init__ method but is there a cleaner way using something like the syntax above?


Solution

  • python 3.8 introduced a new type called Literal that can be used here:

    from dataclasses import dataclass
    from typing import Literal
    
    @dataclass
    class Person:
        name: Literal['Eric', 'John', 'Graham', 'Terry'] = 'Eric'
    

    Type checkers like mypy have no problems interpreting it correctly, Person('John') gets a pass, and Person('Marc') is marked as incompatible. Note that this kind of hint requires a type checker in order to be useful, it won't do anything on its own when you're just running the code.

    If you're on an older python version and can't upgrade to 3.8, you can also get access to the Literal type through the official pip-installable backport package typing-extensions, and import it with from typing_extensions import Literal instead.


    If you need to do actual checks of the passed values during runtime, you should consider using pydantic to define your dataclasses instead. Its main goal is to extend on dataclass-like structures with a powerful validation engine which will inspect the type hints in order to enforce them, i.e. what you considered to write by hand in the __post_init__.