Given this example:
import typing
def foo(bar: int = None):
pass
typing.get_type_hints(foo)
The type hint for bar
is typing.Union[int, None]
. How do I get int
from that? Neither the __args__
nor __parameters__
property seems to work in Python 3.5.2.
More concretely, I'm trying to write a generic decorator that inspects the signature of a function and does specific things to the arguments. For that it needs to get the class from an annotation such as Optional[T]
to then work with T
:
annot = typing.Optional[T]
cls = # MAGIC?!
assert cls is T
In 3.5.2
, to get the parameters for a Union
, you'll have to use __union_params__
.
>>> from typing import Union
>>> d = Union[int, str]
>>> print(*d.__union_params__)
<class 'int'> <class 'str'>
This, unfortunately, seems to only apply until 3.5.2
, it was changed in 3.5.3
to use __args__
:
>>> from typing import Union
>>> t = Union[int, str]
>>> t.__union_params__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: '_Union' object has no attribute '__union_params__'
>>> print(*t.__args__)
<class 'int'> <class 'str'>
and has stayed __args__
in later versions (3.6
and 3.7
).
This is due to the provisional status of the typing module. Many aspects of the internal API are changing between micro version so you'll probably have to deal with a lot of obscure changes.
In these cases I prefer to simply consult the implementation. In 3.5.2 this is the __repr__
of Union
:
def __repr__(self):
r = super().__repr__()
if self.__union_params__:
r += '[%s]' % (', '.join(_type_repr(t)
for t in self.__union_params__))
return r
This suggests that the class is stored in the __union_params__
attribute:
typing.get_type_hints(foo)['bar'].__union_params__[0] is T
This was however changed to __args__
in the commit 5fc25a873cfdec27e46f71e62c9b65df5667c1b4
for 3.5.3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With