Background
The typing module supports subscriptable types. Here is an example use case:
from typing import List def foo(bar: List[int]): pass However, when you try to use this with isinstance, it fails:
>>> from typing import List >>> my_list = [1, 2, 3] >>> isinstance(my_list, List[int]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 719, in __instancecheck__ return self.__subclasscheck__(type(obj)) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 722, in __subclasscheck__ raise TypeError("Subscripted generics cannot be used with" TypeError: Subscripted generics cannot be used with class and instance checks Code
So, I wrote a program which can test for subscripted types. Here is my code:
class Union: def __init__(self, type1, type2): if not isinstance(type1, (type, Type)) or not isinstance(type2, (type, Type)): raise ValueError(f'{type1!r}, {type2!r} are not types') self.types = type1, type2 def __str__(self): return self.types[0].__name__ + ' | ' + self.types[1].__name__ def __repr__(self): return str(self) @property def __name__(self): return str(self) class Type: def __init__(self, dtype, of=None): if isinstance(dtype, Type): self.dtype = dtype.dtype elif isinstance(dtype, (type, Union)): self.dtype = dtype else: raise ValueError(f'{dtype!r} is not a type') if of is not None and not isinstance(of, (Type, Union, type)): raise ValueError(f'{of!r} is not a type') self.of = of def __str__(self): if self.of is not None: return f'{self.dtype.__name__}[{str(self.of.__name__)}]' else: return str(self.dtype.__name__) def __repr__(self): return str(self) def __getitem__(self, cls): return Type(self, cls) def __or__(self, other): return Union(self, other) def __ror__(self, other): return Union(other, self) @property def __name__(self): return str(self) def IsInstance(obj, dtype): if isinstance(dtype, type): return isinstance(obj, dtype) elif isinstance(dtype, Type): if dtype.of is None: return isinstance(obj, dtype.dtype) return all(IsInstance(item, dtype.of) for item in obj) elif isinstance(dtype, Union): return any(IsInstance(obj, t) for t in dtype.types) Bool = Type(bool) Dict = Type(dict) Float = Type(float) Int = Type(int) List = Type(list) Set = Type(set) Str = Type(str) Tuple = Type(tuple) Notes
Unionis the equivalent oftyping.Union, but it is a bit different. You can get aUnionby either:- Using
Union(int, float) - Using
Int | Float
- Using
- To do the instance check, use
IsInstance, notisinstance. For example:- Use
IsInstance([1, 2, 3], List[int])
- Use