I am working with a generic class in python.
The corresponding TypeVar is restricted to a finite amount of (invariant) types.
Because it is of some importance what exact type it is at runtime, I specify the type at initialization.
Later, I have some code where I want to narrow to certain types.
Because I want to narrow to this specific type, the natural way seems to use [stored_type] is [desired_type].
Unfortunately, mypy as well as pyright do not perform any narrowing.
However, if I use isinstance([stored_type], type([desired_type]), it narrows as intended.
Also, a similar case where I use a Union instead, the narrowing using is works.
I am currently using isinstance because it works for the type checker, but as far as I know is provides the stronger check here and is what I actually want.
Is there a good reason for the current behaviour? Why is the narrowing with is less strict than with isinstance?
from typing import reveal_type
class MyClass1:
def __init__(self):
pass
class MyClass2:
def __init__(self, arg: int):
pass
class MyGeneric[V: (MyClass1, MyClass2)]:
def __init__(self, member_type: type[V]):
if member_type is MyClass1:
reveal_type(member_type) # type[V@MyGeneric]
if isinstance(member_type, type(MyClass1)):
reveal_type(member_type) # type[MyClass1]*
def mymethod(self, member_type: type[MyClass1] | type[MyClass2]):
if member_type is MyClass1:
reveal_type(member_type) # type[MyClass1]
class Child(MyClass1): ...- yes,Vwill still be solved toMyClass1, but the runtime type won't magically change, so yourischeck won't work.__init__method, so this would be a feature – we do not know what arguments the child class uses for__init__, so the check should only succed for the base class typetyping.cast- you can't enforce this statically in mypy. Though positive narrowing byisin this case should be safe, consider it a missing mypy feature (or perhaps even a bug, given that it works without typevar - it may be easy to implement). Please check if it's already reported at github.com/python/mypy/issues and report if not, we'll take a look.__init__func. However, it seems mypy fails to detect when a child class changes the interface for__init__such that it no longer an adhere to the protocol specification.@classmethodfactory functions? That way you could sure of a safe way to create instances of the type.