5

I'm trying to implement Nodes and Edges for a graph. Here is my code:

from typing import NamedTuple, List

class Node(NamedTuple):
    name: str
    edges: List[Edge]

class Edge(NamedTuple):
    src: Node
    dest: Node

This raises an error because the Edge type is not defined when Node is created.

NameError: name 'Edge' is not defined

Switching the definitions around doesn't work because Edge also refers to Node.

How can I make it work?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Michael Hewson
  • 1,444
  • 13
  • 21

2 Answers2

6

Use string literals.

from typing import NamedTuple, List

class Node(NamedTuple):
    name: str
    edges: List['Edge']

class Edge(NamedTuple):
    src: Node
    dest: Node

The details are in PEP-484, under the "Forward References" section:

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.

wim
  • 338,267
  • 99
  • 616
  • 750
5

You can use string literals; they'll be evaluated later:

class Node(NamedTuple):
    name: str
    edges: List['Edge']

See the Forward References section of PEP 484 -- Type Hints:

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.

For NamedTuple objects, forward references are stored explicitly for later dereferencing:

>>> Node._field_types
{'name': <class 'str'>, 'edges': typing.List[_ForwardRef('Edge')]}

which a type checker can later dereference from the locals and globals:

>>> typing._eval_type(Node._field_types['edges'], globals(), locals())
typing.List[__main__.Edge]
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343