Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the class as a type hint for arguments in its methods [duplicate]

The code I have included below throws the following error:

NameError: name 'Vector2' is not defined  

at this line:

def Translate (self, pos: Vector2): 

Why does Python not recognize my Vector2 class in the Translate method?

class Vector2:      def __init__(self, x: float, y: float):          self.x = x         self.y = y      def Translate(self, pos: Vector2):          self.x += pos.x         self.y += pos.y 
like image 472
Vanitas Avatar asked Oct 14 '16 17:10

Vanitas


People also ask

How do you write a class hint in Python?

In a type hint, if we specify a type (class), then we mark the variable as containing an instance of that type. To specify that a variable instead contains a type, we need to use type[Cls] (or the old syntax typing. Type ).

What does type () do in Python?

Python has a lot of built-in functions. The type() function is used to get the type of an object. When a single argument is passed to the type() function, it returns the type of the object. Its value is the same as the object.

How do you use type hints in Python?

Here's how you can add type hints to our function: Add a colon and a data type after each function parameter. Add an arrow ( -> ) and a data type after the function to specify the return data type.

What is __ new __ in Python?

The __new__() is a static method of the object class. When you create a new object by calling the class, Python calls the __new__() method to create the object first and then calls the __init__() method to initialize the object's attributes.


2 Answers

Because when it encounters Translate (while compiling the class body), Vector2 hasn't been defined yet (it is currently compiling, name binding hasn't been performed); Python naturally complains.

Since this is such a common scenario (type-hinting a class in the body of that class), you should use a forward reference to it by enclosing it in quotes:

class Vector2:         # __init__ as defined      def Translate(self, pos: 'Vector2'):             self.x += pos.x         self.y += pos.y 

Python (and any checkers complying to PEP 484) will understand your hint and register it appropriately. Python does recognize this when __annotations__ are accessed through typing.get_type_hints:

from typing import get_type_hints  get_type_hints(Vector2(1,2).Translate) {'pos': __main__.Vector2} 

This has been changed as of Python 3.7; see abarnert's answer below.

like image 123
Dimitris Fasarakis Hilliard Avatar answered Sep 28 '22 16:09

Dimitris Fasarakis Hilliard


The feature you're asking for is called forward (type) references, and it has been added to Python as of 3.7 (in PEP 563).1 So this is now valid:

from __future__ import annotations class C:     def spam(self, other: C) -> C:         pass 

Notice the __future__ statement. This will be necessary until 4.0.

Unfortunately, in Python 3.6 and earlier, this feature is not available, so you have to use string annotations, as explained in Jim Fasarakis Hilliard's answer.

Mypy already supports forward declarations, even when run under Python 3.6—but it doesn't do you much good if the static type checker says your code is fine but the interpreter raises a NameError when you try to actually run it.


1. This was already discussed as a possible feature in PEP 484, but deferred until later, after people had more experience using forward declarations in annotations. PEP 563/Python 3.7 is that "later".

like image 30
abarnert Avatar answered Sep 28 '22 14:09

abarnert