So I have this metaclass that I want to use for automatic registration of new components, i.e. subclasses of some base component class. When registering a new component, its instance is expected to be passed to the register_component() function that handles that.
Metaclass code (stripped-down version):
class AutoRegisteredMeta(type):
def __new__(metacls, name, bases, attrs):
# ... (omitted) check if "name" has already been registered ...
new_class = super().__new__(metacls, name, bases, attrs)
register_component(name, new_class()) # RuntimeError(super(): empty __class__ cell)
return new_class
The problem is that invoking new_class()
results in an error - but not for all classes. After some experimenting I realized that this only happens if a subclass calls super().__init__()
in its own __init__()
method.
Sample component and the base class:
class BaseComponent(metaclass=AutoRegisteredMeta):
def __init__(self):
# do some work here ...
class ComponentFoo(BaseComponent):
def __init__(self):
super().__init__() # <--- RuntimeError occurs here
self.foo = 'bar'
What am I doing wrong here? Reading this I found out that I probably shouldn't be doing instantiation in metaclass'es __new__()
or __init__()
, right? Can this perhaps be circumvented somehow?
Also, some explanation in layman's terms would be nice, I don't know much of the internals of the CPython implementation.
Thanks in advance!
(FWIW, I use Python 3.3.6, Ubuntu)
EDIT: I'm adding the minimal example that was requested, you can run it directly and see the error in action yourself.
#!/usr/bin/env python3
class AutoRegisteredMeta(type):
def __new__(metacls, name, bases, attrs):
new_class = super().__new__(metacls, name, bases, attrs)
new_class() # <--- RuntimeError can occur here
return new_class
class BaseComponent(metaclass=AutoRegisteredMeta):
def __init__(self):
print("BaseComponent __init__()")
class GoodComponent(BaseComponent):
def __init__(self):
print("GoodComponent __init__()")
class BadComponent(BaseComponent):
def __init__(self):
print("BadComponent __init__()")
super().__init__() # <--- RuntimeError occurs because of this
maybe this works: