I'm trying to wrap my head around the precise order of operations and interactions when a Python class definition involves a metaclass, a init_subclass
method, and a class decorator.
class Meta(type):
def __new__(mcs, name, bases, dct):
print(f"Meta.__new__ called for {name}")
# Perform some modification to the class dictionary
dct['meta_attr'] = f"Value from {mcs.__name__}"
return super().__new__(mcs, name, bases, dct)
def __init__(cls, name, bases, dct):
print(f"Meta.__init__ called for {name}")
super().__init__(cls, name, bases, dct)
cls.meta_init_attr = f"Initialized by {cls.__class__.__name__}"
def class_decorator(cls):
print(f"Class decorator called for {cls.__name__}")
cls.decorated_attr = "Decorated!"
return cls
@class_decorator
class MyBase(metaclass=Meta):
def __init_subclass__(cls, **kwargs):
print(f"MyBase.__init_subclass__ called for {cls.__name__}")
super().__init_subclass__(**kwargs)
cls.base_subclass_attr = "From MyBase __init_subclass__"
def __init__(self):
print("MyBase instance __init__ called")
self.instance_attr = "Instance created"
print("\nDefining MyDerived:")
class MyDerived(MyBase):
def __init_subclass__(cls, **kwargs):
print(f"MyDerived.__init_subclass__ called for {cls.__name__}")
super().__init_subclass__(**kwargs)
cls.derived_subclass_attr = "From MyDerived __init_subclass__"
def __init__(self):
print("MyDerived instance __init__ called")
super().__init__()
print("\nCreating MyDerived instance:")
instance = MyDerived()
print("\nAttributes on MyDerived class:")
print(f"MyDerived.meta_attr: {hasattr(MyDerived, 'meta_attr')}")
print(f"MyDerived.meta_init_attr: {hasattr(MyDerived, 'meta_init_attr')}")
print(f"MyDerived.decorated_attr: {hasattr(MyDerived, 'decorated_attr')}")
print(f"MyDerived.base_subclass_attr: {hasattr(MyDerived, 'base_subclass_attr')}")
print(f"MyDerived.derived_subclass_attr: {hasattr(MyDerived, 'derived_subclass_attr')}")
print("\nAttributes on instance:")
print(f"instance.instance_attr: {hasattr(instance, 'instance_attr')}")
Which of the listed attributes (meta_attr
, meta_init_attr
, decorated_attr
, base_subclass_attr
, derived_subclass_attr
, instance_attr
) will be present on the MyDerived
class itself, and which on the instance
of MyDerived
?
cls
from line 10, e.g.super().__init__(name, bases, dct)
.