Reputation: 977
I'm trying to get a better understanding of python class system. This question is intended only to satisfy my curiosity.
Is it possible to use somehow a class instance as a parent class for another class. So far what I tried to do is
class A:
pass
a = A()
class B(a):
pass
and it gives following error: TypeError: object() takes no parameters
class Meta(type):
pass
class A:
pass
a = A()
class B(a, metaclass=Meta):
pass
and it gives this error TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I'm wondering, is it possible to somehow proxy all of the class instance methods to metaclass, so my instance would behave as a class
Upvotes: 0
Views: 201
Reputation: 12157
OK, so it is possible to hack if you have control over the base class (either using metaclasses or __init_subclass__
(python 3.6 or later))
class A:
x = 1
def __init_subclass__(cls, inst, **kwargs):
super().__init_subclass__(**kwargs)
for k, v in vars(inst).items():
if k not in dir(cls): # i.e. don't override but remove if you want to
setattr(cls, k, v)
a = A()
a.y = 2
class B(A, inst=a):
pass
B.x # --> 1
B.y # --> 2
You're sort of on the right tracks with your second example. Yes it is possible.
class Meta(type): pass
class A(metaclass=Meta): pass
class B(A): pass
issubclass(B, A) # --> True
isinstance(B, Meta) # --> True
Thats because A
is an instance of Meta
(thats what a metaclass means, a class whose instance is also a class). Hence B
is a subclass of an instance of Meta
.
So yes, you could set for example
class Meta(type):
def __init__(cls, *args, **kwargs):
cls.x = 1
super().__init__(cls, *args, **kwargs)
class A(Meta):
def __init__(self):
self.y = 2
A.x # 1 (acts as an instance of Meta)
a = A()
a.y # 2 (acts as an instance of A)
a.x # AttributeError (does not act as an instance of Meta)
Upvotes: 0
Reputation: 77892
Is it possible to use somehow a class instance as a parent class for another class
Well, actually that's always the case since classes ARE instances (of their metaclass). But then the class of the instance you want to use as a parent class (yeah, re-read it thrice...) must behave as if it was a genuine metaclass - which can rapidily become impractical.
I'm wondering, is it possible to somehow proxy all of the class instance methods to metaclass, so my instance would behave as a class
There might be a way indeed (overriding __getattr__()
or __getattribute__()
), but devil is in the details and chances are that by the time you make this rube goldberg contraption "kind-of-work-with-severe-limitations-and-corner-cases", you will wonder if that was really worth the pain.
Note that OTHO both composition/delegation and dynamic (runtime) creation / modification of classes is absurdly easy in Python so I can hardly think of a problem that would be better solved by (ab)using an instance as a parent class.
Upvotes: 1
Reputation: 25789
Your instance needs to be a type
in order to be used in inheritance chains. For example:
class A(type):
pass
a = A(str) # you need to pass the type's `type` to the construcor
class B(a):
pass
That being said, there's little, if no practical application for this that I can think of - or rather whatever you achieve this way will be easier and more Pythonic to achieve through normal inheritance and metaclasses.
Upvotes: 0
Reputation: 26281
Every instance has a __class__
attribute that refers to the underlying class
structure.
Knowing this, you can actually do the following:
class A(object):
def foo(self):
return 'hello'
a = A()
class B(a.__class__):
pass
b = B()
print(b.foo()) # Prints 'hello'
Alternatively, you can also use type:
class B(type(a)):
pass
b = B()
print(b.foo()) # Prints 'hello'
Upvotes: 0