3

On this code:

class Obj():
    def a(self):
        pass


class ObjChild(Obj):
    def b(self):
        pass


class A:
    def __init__(self, obj: Obj):
        self.obj = obj


class B(A):
    def __init__(self, obj: ObjChild):
        super().__init__(obj)
        
    def kuku(self):
        self.obj.b()

Pycharm warns me about the last line that:

Unresolved attribute reference 'b' for class 'Obj'

But I type-hinted the obj that is being passed in the __init__ to be ObjChild, so it should know statically that self.obj is a ObjChild instance, and would have the b method.

How can I make Pycharm realize that? It messes up my autocompletions in the project.

omer mazig
  • 965
  • 2
  • 10
  • 17
  • 1
    Probably adding a `obj: ObjChild` type hint at the class level would fix it. – deceze Dec 23 '21 at 14:42
  • The problem is probably that Pycharm doesn't conclude that `super().__init__(obj)` sets `self.obj` to `obj`. One solution might then be to replace `self.obj.b()` with just `obj.b()`. – md2perpe Dec 23 '21 at 14:51
  • to me your are initalising A with a class which you have told is of type obj. so why would you expect the obj class to know about `b` since its not part of the obj class it only exists in the objChild class. inheretance works up the way, objChild will know about attribute in obj but not the otherway around – Chris Doyle Dec 23 '21 at 14:55
  • @md2perpe. That's clearly not a solution – Mad Physicist Dec 23 '21 at 15:09
  • I edited my example to better reflect my issue (@md2perpe solution was to the old example). I got my answer though, so thank you! – omer mazig Dec 23 '21 at 15:10
  • 2
    @MadPhysicist. It was a solution when I wrote my answer and the code looked different. – md2perpe Dec 23 '21 at 15:15

1 Answers1

3

Make A a Generic:

from typing import Generic, TypeVar


class Obj:
    def a(self):
        pass


_Obj = TypeVar('_Obj', bound=Obj)


class ObjChild(Obj):
    def b(self):
        pass


class A(Generic[_Obj]):
    def __init__(self, obj: _Obj):
        self.obj = obj


class B(A[ObjChild]):
    def __init__(self, obj: ObjChild):
        super().__init__(obj)
        self.obj.b()

Unless you make A a generic, there's no connection between passing an ObjChild to A.__init__ and A.obj being an ObjChild.

Samwise
  • 68,105
  • 3
  • 30
  • 44