Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name not defined in type annotation [duplicate]

I'm currently working on creating a python linear algebra module for fun and for practice with the language. I recently tried to add type annotations to the module, as such:

class Vector:      # Various irrelevant implementation details      def __add__(self, other: Vector) -> Vector:         # More implementation details.... 

However, when I try to import this, it spits out a NameError: Name 'Vector' is not defined. I acknowledge that this question has already been answered, in a form, here, but it doesn't seem to wholly provide an answer for my situation.

What I'd like to know:

  • I've defined the class literally in this file. Why does it say the name isn't defined?
  • How do I define Vector in such a way that it can be used for annotations (as a type)?
like image 679
MutantOctopus Avatar asked Mar 29 '16 14:03

MutantOctopus


2 Answers

You have a forward declaration; functions (to be bound as methods) are created before the class is, so the name Vector doesn't yet exist. Only when all of the class body has been executed, can Python create the class object and bind the name Vector to it.

Simply use a string with the name instead:

class Vector:      # Various irrelevant implementation details      def __add__(self, other: 'Vector') -> 'Vector':         # More implementation details.... 

This doesn't affect how your IDE sees the declaration; strings are looked up once the whole module is loaded, and are resolved as a valid Python expression in the current context. Since the class Vector exists once the whole module is loaded, the string 'Vector' can properly be converted to the class object.

Also see the specification on 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.

[...]

The string literal should contain a valid Python expression [...] and it should evaluate without errors once the module has been fully loaded.

As of Python 3.7 you can make all annotations in a given module behave like forward annotations (without enclosing them in a string literal), by adding the from __future__ import annotations directive at the top of the module. In Python 3.10 and up this has become the default behaviour. See PEP 563 -- Postponed Evaluation of Annotations. Note that outside of annotations you may still need to use forward reference syntax (string literals), e.g. in a type alias (which is a regular variable assignment as far as Python is concerned).

like image 62
Martijn Pieters Avatar answered Oct 14 '22 04:10

Martijn Pieters


If you are using Python 3.7 and above. Take a look at Postponed evaluation of annotations

Since Python 3.7, it will be allowed, just add:

from __future__ import annotations 

And also note that

It will become the default in Python 3.10.

like image 21
vishes_shell Avatar answered Oct 14 '22 03:10

vishes_shell