Type hint for 'other' in magic methods?

1.9k views Asked by At
class Interval(object):
    def __sub__(self, other: Interval):
        pass

The way it is I get a 'NameError: name 'Interval' is not defined'. Can someone tell me which type would be correct here?

1

There are 1 answers

0
Kevin On BEST ANSWER

The class doesn't exist until after Python finishes executing all the code inside the class block, including your method definitions.

Just use a string literal instead, as suggested in PEP 484:

class Interval(object):
    def __sub__(self, other: 'Interval'):
        pass

Note that it's perfectly fine to refer to the class inside a method:

class Interval(object):
    def __sub__(self, other: 'Interval'):
        Interval.do_something()

This is only a problem if you need to use it in a method signature or directly inside the class block.


As of Python 3.7, the above workaround is no longer necessary (but still perfectly valid, so you can and should continue using it if you need to support older versions of Python). Instead, put the following at the top of each module to enable forward references within that module:

from __future__ import annotations

This will cause all annotations to be lazily evaluated on lookup, so that you can refer to classes within their definitions, or even before their definitions. In short, it makes every "reasonable" annotation mean what you (probably) wanted it to mean.

Finally, if you need to inspect type annotations, be sure you are using typing.get_type_hints() instead of the .__annotations__ special attribute. This function correctly handles both the old and the new way of doing things, as well as a few other nuances of the type hinting rules such as automatic Optional[T] when the default value is None. It is the comfortable and future-proof way to examine the type hints attached to an arbitrary Python object.