-
-
Save MathiasSven/07512a2fdf6de052b80a1a1db55f9f69 to your computer and use it in GitHub Desktop.
`type[T]` covariance issues
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import annotations | |
from contextlib import suppress | |
from typing import Any, ClassVar | |
from typing_extensions import reveal_type | |
class Foo: ... | |
class SubFoo(Foo): | |
def bar(self) -> int: return 5 | |
class A: | |
clsvar: ClassVar[Foo] = Foo() | |
def foo(self: A, x: int) -> int: | |
return x | |
class SubA1(A): | |
num: int = 42 | |
def __init__(self, num: int) -> None: ... | |
def foo(self: SubA1, x: int) -> int: | |
return self.num + x | |
class SubA2(A): | |
clsvar: ClassVar[SubFoo] = SubFoo() | |
def foo(self: SubA2, x: int) -> int: | |
return self.clsvar.bar() + x | |
def factory_one() -> type[A]: return SubA1 | |
def factory_two() -> type[A]: return SubA2 | |
def main() -> None: | |
main_foo = factory_one().foo | |
reveal_type(main_foo) # Revealed as "(self: A, x: int) -> int" | |
# Bound method problem | |
with suppress(AttributeError): | |
main_foo(A(), 2) # Type checks, but runtime error | |
print("Won't print") | |
my_cls = factory_one() # This is checked as "__main__.A" but it is "__main__.SubA1" | |
# Constructor problem | |
with suppress(TypeError): | |
my_instance = my_cls() # Type checks, but runtime error | |
print("Won't print") | |
my_cls_two = factory_two() | |
reveal_type(my_cls_two.clsvar) # Revealed type is "__main__.Foo" | |
my_cls_two.clsvar = Foo() | |
# ClassVar problem | |
with suppress(AttributeError): | |
my_cls_two().foo(41) | |
print("Won't print") | |
# Granted, instances have the same problem, but I think it is | |
# unresonable to 'fix' this | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment