I want to have an instance of class registered when the class is defined. Ideally the code below would do the trick.
registry = {}
def register( cls ):
registry[cls.__name__] = cls() #problem here
return cls
@register
class MyClass( Base ):
def __init__(self):
super( MyClass, self ).__init__()
Unfortunately, this code generates the error NameError: global name 'MyClass' is not defined.
What’s going on is at the #problem here line I’m trying to instantiate a MyClass but the decorator hasn’t returned yet so it doesn’t exist.
Is the someway around this using metaclasses or something?
Yes, meta classes can do this. A meta class’
__new__method returns the class, so just register that class before returning it.The previous example works in Python 2.x. In Python 3.x, the definition of
MyClassis slightly different (whileMetaClassis not shown because it is unchanged – except thatsuper(MetaClass, cls)can becomesuper()if you want):As of Python 3.6 there is also a new
__init_subclass__method (see PEP 487) that can be used instead of a meta class (thanks to @matusko for his answer below):[edit: fixed missing
clsargument tosuper().__new__()][edit: added Python 3.x example]
[edit: corrected order of args to super(), and improved description of 3.x differences]
[edit: add Python 3.6
__init_subclass__example]