Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the literal out of a python Literal type, at runtime?

How can I get the literal value out of a Literal[] from typing?

from typing import Literal, Union

Add = Literal['add']
Multiply = Literal['mul']
Action = Union[Add,Multiply]

def do(a: Action):
    if a == Add:
        print("Adding!")
    elif a == Multiply:
        print("Multiplying!")
    else:
        raise ValueError

do('add')

The code above type checks since 'add' is of type Literal['add'], but at runtime, it raises a ValueError since the string 'add' is not the same as typing.Literal['add'].

How can I, at runtime, reuse the literals that I defined at type level?

like image 699
LudvigH Avatar asked Dec 03 '19 18:12

LudvigH


1 Answers

The typing module provides a function get_args which retrieves the arguments with which your Literal was initialized.

>>> from typing import Literal, get_args
>>> l = Literal['add', 'mul']
>>> get_args(l)
('add', 'mul')

However, I don't think you gain anything by using a Literal for what you propose. What would make more sense to me is to use the strings themselves, and then maybe define a Literal for the very strict purpose of validating that arguments belong to this set of strings.

>>> def my_multiply(*args):
...    print("Multiplying {0}!".format(args))
...
>>> def my_add(*args):
...    print("Adding {0}!".format(args))
...
>>> op = {'mul': my_multiply, 'add': my_add}
>>> def do(action: Literal[list(op.keys())]):
...    return op[action]

Remember, a type annotation is essentially a specialized type definition, not a value. It restricts which values are allowed to pass through, but by itself it merely implements a constraint -- a filter which rejects values which you don't want to allow. And as illustrated above, its argument is a set of allowed values, so the constraint alone merely specifies which values it will accept, but the actual value only comes when you concretely use it to validate a value.

like image 59
tripleee Avatar answered Sep 28 '22 02:09

tripleee