how to get derived class name from base class
Question:
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’.
Answers:
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"
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'
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.
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?
In your example you do not need to know the class, you just call the method by referring to the class instance:
# 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'] = object.title()
But do not use object
as a variable name, you hide the built-in name.
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
Python classes have the __subclasses__
magic method which can be used to see which in-scope classes are currently and derived from a given parent class.
# related.py
class Parent: ...
class Child(Parent): ...
>>> from related import Parent
>>> Parent.__subclasses__()
[<class 'related.Child'>]
These classes are weak-references to any in-scope derivative class at the time the Parent
class is accessed.
# not_related.py
class StepChild(Parent): ...
>>> from related import Parent
>>> Parent.__subclasses__()
[<class '__main__.Child'>]
>>> from not_related import StepChild
>>> Parent.__subclasses__()
[<class 'related.Child'>, <class 'not_related.StepChild'>]
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’.
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"
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'
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.
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?
In your example you do not need to know the class, you just call the method by referring to the class instance:
# 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'] = object.title()
But do not use object
as a variable name, you hide the built-in name.
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
Python classes have the __subclasses__
magic method which can be used to see which in-scope classes are currently and derived from a given parent class.
# related.py
class Parent: ...
class Child(Parent): ...
>>> from related import Parent
>>> Parent.__subclasses__()
[<class 'related.Child'>]
These classes are weak-references to any in-scope derivative class at the time the Parent
class is accessed.
# not_related.py
class StepChild(Parent): ...
>>> from related import Parent
>>> Parent.__subclasses__()
[<class '__main__.Child'>]
>>> from not_related import StepChild
>>> Parent.__subclasses__()
[<class 'related.Child'>, <class 'not_related.StepChild'>]