how to get derived class name from base class

39,403

Solution 1

You can use x.__class__.__name__ to retrieve the class name as a string, e.g.

class Person:
    pass

class Manager(Person):
    pass

class Employee(Person):
    pass

def get_class_name(instance):
    return instance.__class__.__name__

>>> m = Manager()
>>> print get_class_name(m)
Manager
>>> print get_class_name(Employee())
Employee

Or, you could use isinstance to check for different types:

>>> print isinstance(m, Person)
True
>>> print isinstance(m, Manager)
True
>>> print isinstance(m, Employee)
False

So you could do something like this:

def handle_person(person):
    if isinstance(person, Manager):
        person.read_paper()     # method of Manager class only
    elif isinstance(person, Employee):
        person.work_hard()      # method of Employee class only
    elif isinstance(person, Person):
        person.blah()           # method of the base class
    else:
        print "Not a person"

Solution 2

I don't know if this is what you want, and the way you'd like it implemented, but here's a try:

>>> class Person(object):
    def _type(self):
        return self.__class__.__name__


>>> p = Person()
>>> p._type()
'Person'
>>> class Manager(Person):
    pass

>>> m = Manager()
>>> m._type()
'Manager'
>>> 

Pros: only one definition of the _type method.

Solution 3

Python objects provide a __class__ attribute which stores the type used to make that object. This in turns provides a __name__ attribute which can be used to get the name of the type as a string. So, in the simple case:

class A(object):
    pass
class B(A):
    pass

b = B()
print b.__class__.__name__

Would give:

'B'

So, if I follow your question correctly you would do:

m = Manager()
print m.__class__.__name__
'Manager'

Solution 4

Would you be looking for something like this?

>>> class Employee:
...     pass
... 
>>> class Manager(Employee):
...     pass
... 
>>> e = Employee()
>>> m = Manager()
>>> print e.__class__.__name__
Employee
>>> print m.__class__.__name__
Manager
>>> e.__class__.__name__ == 'Manager'
False
>>> e.__class__.__name__ == 'Employee'
True

Solution 5

The best way to "do this" is to not do it. Instead, create methods on Person that are overridden on Manager or Employee, or give the subclasses their own methods that extend the base class.

class Person(object):
    def doYourStuff(self):
        print "I'm just a person, I don't have anything to do"

class Manager(object):
    def doYourStuff(self):
        print "I hereby manage you"

class Employee(object):
    def doYourStuff(self):
        print "I work long hours"

If you find yourself needing to know in the base class which subclass is being instantiated, your program probably has a design error. What will you do if someone else later extends Person to add a new subclass called Contractor? What will Person do when the subclass isn't any of the hard-coded alternatives it knows about?

Share:
39,403
Sadiksha Gautam
Author by

Sadiksha Gautam

Likes learning new technologies Ruby on Rails Rockstar ;) Rails girls coach

Updated on July 21, 2022

Comments

  • Sadiksha Gautam
    Sadiksha Gautam almost 2 years

    I have a base class Person and derived classes Manager and Employee. Now, what I would like to know is the object created is Manager or the Employee.

    The person is given as belows:

    from Project.CMFCore.utils import getToolByName
    schema = getattr(Person, 'schema', Schema(())).copy() + Schema((TextField('FirstName', required = True, widget = StringWidget(label='First Name', i18n_domain='project')), TextField('Last Name', required = True, widget = StringWidget(label='Last Name', i18n_domain='i5', label_msgid='label_pub_city'))
    class Manager(BaseContent):
      def get_name(self):
        catalog = getToolByName(self, "portal_catalog")
          people = catalog(portal_type='Person')
          person={}
          for object in people:
            fname = object.firstName
            lname = object.lastName
            person['name'] = fname+' '+ lname
            # if the derived class is Employee then i would like go to the method title of employee and if its a Manager then go to the title method of Manager
            person['post'] = Employee/Manager.title()
          return person
    

    For Manager and employees they are like (employee is also similar but some different methods)

    from Project.Person import Person
    class Manager(Person):
        def title(self):
          return "Manager"
    

    For Employee the title is 'Employee'. When I create a Person it is either Manager or the Employee. When I get the person object the class is Person but I would like to know whether it is from the derived class 'Manager' or 'Employee'.

  • Tom Russell
    Tom Russell almost 8 years
    Succinct. Nice use of interactive output.
  • martineau
    martineau over 7 years
    Doubtful this is the "best way" or that the OP has a broken design. Simpler to implement as shown in this answer in which the base class has a method that all the subclasses can use (for whatever purpose they choose).
  • Saurav Kumar
    Saurav Kumar over 7 years
    Many Thanks.. This is what I was looking for!
  • Chandan
    Chandan about 6 years
    What if I have made 3 types of User classes and I want to know about the class of the object I get from request.user. request.user returns an object of User class.
  • Emmanuel
    Emmanuel about 6 years
    I'm sorry @Chandan bu t I don't understand your question. Can you be more precise?
  • Chandan
    Chandan about 6 years
    I have a User class "class User(AbstractBaseUser)", "class Manager(User)" and "class Employee(User)". Django creates tables for Manager, Employee as well as for User. If I type in the shell: u1 = User.objects.all()[0], now I want to know if u1 is an Employee or a Manager. How can I do that? Or am I doing anything wrong here that is why a table for User is being created separately?
  • Emmanuel
    Emmanuel about 6 years
    Ok, you are in the Django context, that was not clear at all... Well, I don't know how Django manages these classes, but I'm pretty sure you can know. What about creating a dedicated post in SO for that?
  • Shlomo Gottlieb
    Shlomo Gottlieb almost 3 years
    What if I want _type to be static? (decorated by @staticmethod)
  • Emmanuel
    Emmanuel almost 3 years
    @ShlomoGottlieb: this completely changes the solution, since this one is based on the object instance via self... I guess you have to define a static method in every derived class, which is not scalable. But you can use @classmethod similarly: def type2(cls): return cls.__name_
  • Shlomo Gottlieb
    Shlomo Gottlieb almost 3 years
    @Emmanuel Very nice! the classmethod solution works as expected.