The problem is that in the following situation, autocompletion in the SubFoo class does not work in Pylance. Pylance only recognize the methods and attributes of the Bar class inside SubFoo class, but not the methods and attributes of the SubBar class. Am I doing the right thing?
class Bar: def method1(self): # do stuff class SubBar(Bar): def method2(self): # do stuff class Foo: def __init__(self, arg: Bar): self.attr: Bar = arg def do_a(self): self.attr.method1() class SubFoo(Foo): def __init__(self, arg: SubBar): super().__init__(arg) def do_b(self): self.attr.method1() # Pylance's autocopmletion recognizes method1() self.attr.method2() # Pylance's autocopmletion doesn't recognize method2()
You’ve declared the type of
Foo.attr to be
Bar. The fact that it happens to be assigned a
SubBar at some point is not the type checker’s concern. If you want to statically know the type of the field based on the subclass, then
Foo should be generic.
from typing import TypeVar, Generic _T = TypeVar("_T", bound=Bar) class Foo(Generic[_T]): def __init__(self, arg: _T): self.attr: _T = arg def do_a(self): self.attr.method1() class SubFoo(Foo[SubBar]): def __init__(self, arg: SubBar): super().__init__(arg) def do_b(self): ...
Now subclasses of
Foo are required to report which subclass of
Bar they expect their constructor to receive, and that type information becomes available statically.
You’ll also want to consider making that type variable covariant, if your use case supports it.