Getting name of subclass from superclass?
Solution 1
Just as an alternative to @poorsod's solution, which works perfectly fine for me, here's another, perhaps simpler variant without class methods, using self.__class__
. Just as self
always points to the current instance, self.__class__
always points to the actual class of that instance.
class bc(object):
def get_subclass_name(self):
return self.__class__.__name__
Example, tested in Python 2.6.6:
>>> class sc1(bc): pass
>>> class sc2(sc1): pass
>>> class sc3(sc2): pass
>>> print sc2().get_subclass_name()
sc2
If this does not work, please be more specific as to what output you expect and what output you are getting instead.
Solution 2
You need a class method.
class bc(Object):
@classmethod
def get_subclass_name(cls):
return cls.__name__
def somemethod(self):
x = self.get_subclass_name()
Normal methods, when invoked, get passed the instance as the first parameter. This is why you see self
everywhere in Python.
When you invoke a class method, however, the concrete class of the instance is passed to the function. We usually use the name cls
, as I have done here.
The classic use case for class methods is alternative constructors. For example, the standard library's dict
class provides a fromkeys
class method, which constructs a new dict from the supplied keys and a single value. You could construct such a dict manually, but the Python developers made life easy for you!
Jonathan
I am a retired software designer and am currently working on aspects of computer recognition of natural language using Python.
Updated on July 23, 2022Comments
-
Jonathan almost 2 years
I have a base class
bc
and a number of subclasses based onbc
.class bc(Object): def get_subclass_name(self): # Retrieve the name of the most derived subclass of this instance pass def somemethod(self): x = self.get_subclass_name() class sc1(bc): pass class sc2(bc) pass
The idea is that when
somemethod()
is invoked on an instance of a subclass ofbc
, it will be able to use the name of the most derived subclass of that instance without needing to know in advance what potential subclasses may exist.I have put together a test case for this:
class base_class(object): @classmethod def get_subclass_name(cls): return cls.__name__ def somemethod(self): print(base_class.get_subclass_name()) class sub_class(base_class): pass sub_class().somemethod()
When this code is run it produces
base_class
rather thansub_class
. -
Jonathan over 10 yearsIf sc is derived from bc, you will get bc as the name, not sc as I want. I have already tried this.
-
tobias_k over 10 yearsWhy not just use
self.__class__
? -
Benjamin Hodgson over 10 years@Jonathan Have I misunderstood your requirements? If you call
get_subclass_name
on an instance ofsc
, it'll return'sc'
. -
Benjamin Hodgson over 10 years@tobias_k Yes, this is roughly equivalent to using
self.__class__
, but it's much more Pythonic (it's both less verbose and more explicit). -
Jonathan over 10 yearsI was looking for sc3 in this instance.
-
tobias_k over 10 yearsPlease explain why.
sc2
is the actual class of the instance, as an instance ofsc2
is created:sc2().get_...
.sc3
is there just for avoiding the ambiguity of "most derived class". -
Jonathan over 10 yearsMany thanks. Your proposal worked just fine, but the proposal using classmethod from @poorsod did not when I would have expected both to yield the same result.
-
tobias_k over 10 years@Jonathan The answer using classmethods works, too. According to your edit you are just using it the wrong way. See my comment below your question above.
-
Anubis almost 10 years@tobias_k in this approach you need to create an instance first, is there any way to get the sub class name (exact requirement in the question), but without creating an instance??
-
tobias_k almost 10 years@Anubis What do you mean? You have a
class c
and want to get it's name? Just doc.__name__
? Or do you want the name of some subclass ofc
? If so, which subclass to take (there could be many) without providing an instance of that subclass? -
Anubis almost 10 years@tobias_k can you please check my question here: stackoverflow.com/q/24953216/1547699