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 Unions 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 Unions 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