1

I am reusing a popular c++ idiom where a class contains a static dictionary of class instances:

class Zzz:
    elements = {}

    def __init__(self, name):
        self._name = name
        Zzz.elements[name] = self

    @staticmethod
    def list_instances():
        for k in Zzz.elements.items():
            print(k)

It worked fine until I added type annotation, now python complains that Zzz is an unknown type: NameError: name 'Zzz' is not defined

from typing import Dict

class Zzz:
    elements: Dict[str,Zzz] = {} <---- here
Georgy
  • 12,464
  • 7
  • 65
  • 73
uuu777
  • 765
  • 4
  • 21

2 Answers2

1

At the time the annotation is "read", Zzz does not yet exist. Python 3.7 still evaluates the annotations at definition time; at which in this case it is still undefined.

This is covered by Pep563:

from __futures__ import annotations
Cedric H.
  • 7,980
  • 10
  • 55
  • 82
  • I wanted to be backward compatible with python 3.5, so I selected the answer below that is using string literal. – uuu777 Apr 17 '20 at 17:17
1

You can forward-reference your type defining it as a string instead.

from typing import Dict

class Zzz:
    elements: Dict[str, 'Zzz']

Edit by the way, you can easily auto-populate this static dictionary implementing a __init_subclass__() method.

class Zzz:
    elements: Dict[str, 'Zzz'] = {}
    name: str

    def __init_subclass__(cls, **kw):
        cls.elements[cls.name] = cls

class ZzzImpl(Zzz):
    name = 'foo'

assert Zzz.elements['foo'] is ZzzImpl
Tomasito665
  • 1,188
  • 1
  • 12
  • 24
  • Using string worked in 3.7 and it will work in 3.5. The latter is a factor while I selected this response. IMHO, splitting class into two levels is an overkill. – uuu777 Apr 17 '20 at 17:17
  • For this example it probably is, but if you have many subclasses it can be handy. For example if you have an abstract base class and you want to automatically "register" new concrete subclasses and index them by given static variable x. I often use this pattern to create factory static methods or functions. – Tomasito665 Apr 17 '20 at 19:57