5

The problem is like this:

class A():
    def foo() -> B:
        pass

class B():
    def bar() -> A:
        pass

This will raise a NameError: name 'B' is not defined.

For the sake of type checking, I'm not willing to change -> B to -> "B". Is there any workaround?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Cauly
  • 370
  • 1
  • 2
  • 12
  • 1
    Does this answer your question? [How do I type hint a method with the type of the enclosing class?](https://stackoverflow.com/questions/33533148/how-do-i-type-hint-a-method-with-the-type-of-the-enclosing-class) – mkrieger1 May 02 '23 at 08:39

3 Answers3

5

You can pass the first reference as a string (Python 3.5+):

class A():
    def foo() -> 'B':
        pass

class B():
    def bar() -> A:
        pass

It's called "forward reference" and was laid out in PEP484. See this answer for more ways and detailed information.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Karl Lorey
  • 1,536
  • 17
  • 21
2

I found a workaround, which is much similar to C or C++.

Tested in Pycharm 3.

class A: pass
class B: pass

class A(object):

    def foo(self, b: B) -> B:

        #CAN auto complete
        b.bar()

        return B()

class B(object):

    def bar(self) -> A:

        return A()

#CAN auto complete
A().foo(B()).bar()
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Cauly
  • 370
  • 1
  • 2
  • 12
  • 1
    Actually, I would only pre-declare B, not both A and B. Like so: `class B: pass # pre-define name B`, so that the reader has less to wonder about. – Lutz Prechelt Mar 18 '14 at 11:25
1

Well, there is no way to directly do it using the annotation syntax, but one can modify the __annotations__ dictionary of a function object.

class A():
    def foo():
        pass

class B():
    def bar() -> A:
        pass

A.foo.__annotations__["return"] = B
Ramchandra Apte
  • 4,033
  • 2
  • 24
  • 44