Reputation: 8247
I have a class hierarchy - which may be multiple inheritance, for example:
class Base:
def __init__(self):
print("Base")
class A(Base):
def __init__(self):
super().__init__()
print("A")
class B(Base):
def __init__(self):
super().__init__()
print("B")
class C(A, B):
def __init__(self):
super().__init__()
print("C")
x = C()
will print
Base
B
A
C
as expected.
what I'd like to do is somehow print Done
after this is all finished, by defining a method or similar in Base
that will be called when C.__init__()
has completed.
What I can't do:
Base.__init__
as that gets called too early.C.__init__
as I want this to apply to all potential subclassesI've tried various things with metaclasses and haven't managed to make anything work yet - any clever ideas?
Upvotes: 0
Views: 36
Reputation: 531215
The call to __init__
is handled by the call to type.__call__
, once __new__
has returned. You could define a metaclass that overrides __call__
to handle your post-init code; I believe this is the only way to avoid having the code be called prematurely whenever you subclass, since __call__
won't be invoked for or by any of the ancestor classes.
class PostInitHook(type):
def __call__(cls, *args, **kwargs):
rv = super().__call__(*args, **kwargs)
print("Done")
return rv
class Base(metaclass=PostInitHook):
def __init__(self):
print("Base")
...
More generally, you could replace print("Done")
a class specific hook, for example,
class PostInitHook(type):
def __new__(metacls, *args, **kwargs):
cls = super().__new__(metacls, *args, **kwargs)
try:
cls._post_init
except AttributeError:
raise TypeError("Failed to define _post_init")
return cls
def __call__(cls, *args, **kwargs):
rv = super().__call__(*args, **kwargs)
rv._post_init()
return rv
class Base(metaclass=PostInitHook):
def __init__(self):
print("Base")
def _post_init(self):
print("Done")
Then
>>> a = A()
Base
A
Done
>>> b = B()
Base
B
Done
>>> c = C()
Base
B
A
C
Done
>>> class D(C):
... def __init__(self):
... super().__init__()
... print("D")
...
>>> d = D()
Base
B
A
C
D
Done
>>>
Upvotes: 3