Let’s say I have a class:
from typing import Literal
class Computer:
    def __init__(self, operation: Literal['floor', 'ceil', 'square']):
        if operation not in ('floor', 'ceil', 'square'):
            raise ValueError(f'Invalid operation "{operation}"')
        self._operation = operation
    # ... lots of methods that use `self._operation`, e.g.
    def is_much_larger(self, value: float) -> bool:
        if self._operation == 'square':
            if value > 1:
                return True
            else:
                return False
        else:
            return False
I would like to maintain the list of viable values, i.e. 'floor', 'ceil', 'square', in only one place. What’s a good recipe for this?
The MyPy docs show some ideas with this suggestion of assert_never but that’s just for MyPy to give an error before runtime, not as a way to maintain a single list of values.
Advertisement
Answer
You can introspect those arguments using the typing module.
>>> import typing
>>> Operation = typing.Literal['floor', 'ceil', 'square']
>>> typing.get_args(Operation)
('floor', 'ceil', 'square')
You could use a type alias then get the values you want using typing.get_args, so something like:
import typing
# in Python >= 3.10 , use explicit type alias:
# Operation: typing.TypeAlias = typing.Literal['floor', 'ceil', 'square'
Operation = typing.Literal['floor', 'ceil', 'square']
class Computer:
    def __init__(self, operation: Operation:
        if operation not in typing.get_args(Operation):
            raise ValueError(f'Invalid operation "{operation}"')
        self._operation = operation
    # ... lots of methods that use `self._operation`, e.g.
    def is_much_larger(self, value: float) -> bool:
        if self._operation == 'square':
            if value > 1:
                return True
            else:
                return False
        else:
            return False
 
						