I currently have this type alias, and some associated functions in my code:
Constant = int
def operation(data: Union[Constant, OtherTypes]):
if isinstance(data, Constant):
# do something
else:
# do something else
Now, I would like for Constant
to also represent another type, say float. This Constant alias is used throughout my codebase, so I'd like to not have to change it everywhere.
I have tried:
Constant = (int, float)
This works nicely with isinstance
, but the Union
s complain that "TypeError: Union[arg, ...]: each arg must be a type."
I have then tried:
Constant = Union[int, float]
Now, the issues come with the isinstance
; I get "TypeError: Subscripted generics cannot be used with class and instance checks"
.
Is there a way to do what I am trying to achieve ?
Thanks.
As mentioned by Pankkake in their answer, for Python 3.10 you can simply do Constant = int | float
and it will work everywhere.
However, if you must support older versions of Python, you can use the solutions provided in How to check a variable against Union type during runtime? by Frank, MSeifert and Richard Xia.
Constant = int | float
def operation(data: Constant | OtherTypes):
if isinstance(data, Constant):
# do something
else:
# do something else
Use the typing.get_args(tp) function to get a tuple with the union types, which you can use inside isinstance
:
from typing import Union, get_args
Constant = Union[int, float]
def operation(data: Union[Constant, OtherTypes]):
if isinstance(data, get_args(Constant)):
# do something
else:
# do something else
get_args
only returns the type's arguments without validating if the type is an Union
or other generic type, which seems enough for your requirement.
If for some reason you also need to check at runtime if the Constant
type is an Union
specifically, use the typing.get_origin(tp) function:
from typing import Union, get_origin
if get_origin(Constant) is Union:
# do something
Before 3.8 the get_args
and get_origin
functions didn't exist, so you needed to use the undocumented attributes __args__
and __origin__
instead.
def operation(data: Union[Constant, OtherTypes]):
if isinstance(data, Constant.__args__):
# do something
else:
# do something else
This still works for 3.10.5 but, since these attributes are undocumented, the snippet above could stop working with no short notice in any future Python version.
Type hints were implemented in Python's 3.5.0 version. Up to 3.5.2 the attribute name to get an union's arguments was __union_params__
:
def operation(data: Union[Constant, OtherTypes]):
if isinstance(data, Constant.__union_params__):
# do something
else:
# do something else
Of course, this attribute only exists for Union
types, so if you need to check if a type is an Union
, check for the existence of the attribute.
Note that this only works up to Python 3.5.2, since in 3.5.3 they changed the attribute name to __args__
.
isinstance
supporting Union
s comes with python 3.10 . As such, starting from that version, the second solution will work.
See https://peps.python.org/pep-0604/ .
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