Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a type hint forward reference

I am playing around with python's 3.5 type hints. I was wondering how can I type hint the return type of a class method.

This is what I had in mind:

>>> class A():
    @classmethod
    def a(cls) -> A:
        pass

Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    class A():
  File "<pyshell#24>", line 3, in A
    def a(cls) -> A:
NameError: name 'A' is not defined

Clearly it does not work. I guess one way would be to do some sort of "forward declaration" like so:

>>> class A():
    pass

>>> class A():
    @classmethod
    def a(cls) -> A:
        pass

But that does not feel "pythonic". How do people normally solve this?

like image 277
Mac Avatar asked Mar 18 '16 02:03

Mac


1 Answers

Forward references When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.

https://www.python.org/dev/peps/pep-0484/#forward-references

The PEP text goes on to provide the following example:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

Apart from the provision for strings, there is a problem with your proposed workaround - if you do:

class A():
    pass

class A():
    @classmethod
    def a(cls) -> A:
        pass

The return value annotated in the (final and real) class A is the object that was carrying A name at the time the class body was processed - and that object is the stub class A. So any tool that would check in a static or runtime analysis the return value of A.a() would find it not to be equal the class A.

So, if a work around as this is ever needed (I had needed it once, I forgot the context -it had not to do with annotations - ah - I recall now: it is in a project that automatically generates Python ctypes wrappers for a specific C library), the way to go is to create one single class, and to augment it afterwards with assignment statements. For your example, that would be:

class A:
    pass

def a(self) -> A:
    pass

A.a = a
del a
like image 89
jsbueno Avatar answered Nov 15 '22 15:11

jsbueno