Reputation: 664
Let B
inherit from A
. Suppose that some of B
's behavior depends on the class attribute cls_x
and we want to set up this dependency during construction of B
objects. Since it is not a simple operation, we want to wrap it in a class method, which the constructor will call. Example:
class B(A):
cls_x = 'B'
@classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = B.cm()
Problem: cm
as well as __init__
will always be doing the same things and their behavior must stay the same in each derived class. Thus, we would like to put them both in the base class and not define it in any of the derived classes. The only difference will be the caller of cm
- either A
or B
(or any of B1
, B2
, each inheriting from A
), whatever is being constructed. So what we'd like to have is something like this:
class A:
cls_x = 'A'
@classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = ClassOfWhateverIsInstantiated.cm() #how to do this?
class B(A):
cls_x = 'B'
I feel like it's either something very simple I'm missing about Python's inheritance mechanics or the whole issue should be handled entirely differently.
This is different than this question as I do not want to override the class method, but move its implementation to the base class entirely.
Upvotes: 1
Views: 395
Reputation: 5958
For ClassOfWhateverIsInstantiated
you can just use self
:
class A:
cls_x = 'A'
@classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = self.cm() # 'self' refers to B, if called from B
class B(A):
cls_x = 'B'
a = A()
print(a.cls_x) # = 'A'
print(A.cls_x) # = 'A'
b = B()
print(b.cls_x) # = 'B'
print(B.cls_x) # = 'B'
To understand this, just remember that class B is inheriting the methods of class A. So when __init__()
is called during B's instantiation, it's called in the context of class B, to which self
refers.
Upvotes: 1
Reputation: 43276
Look at it this way: Your question is essentially "How do I get the class of an instance?". The answer to that question is to use the type
function:
ClassOfWhateverIsInstantiated = type(self)
But you don't even need to do that, because classmethods can be called directly through an instance:
def __init__(self):
self.attr = self.cm() # just use `self`
This works because classmethods automatically look up the class of the instance for you. From the docs:
[A classmethod] can be called either on the class (such as
C.f()
) or on an instance (such asC().f()
). The instance is ignored except for its class.
Upvotes: 1