Python Class Inheritance issue

22,727

Solution 1

Three things:

  1. You need to explicitly call the constructor. It isn't called for you automatically like in C++
  2. Use a new-style class inherited from object
  3. With a new-style class, use the super() method available

This will look like:

class Person(object):
    AnotherName = 'Sue Ann'
    def __init__(self):
        super(Person, self).__init__()
        self.FirstName = 'Tom'
        self.LastName = 'Sneed'

    def get_name(self):
        return self.FirstName + ' ' + self.LastName

class Employee(Person):
    def __init__(self):
        super(Employee, self).__init__()
        self.empnum = 'abc123'

    def get_emp(self):
        print self.AnotherName
        return self.FirstName + ' ' + 'abc'

Using super is recommended as it will also deal correctly with calling constructors only once in multiple inheritance cases (as long as each class in the inheritance graph also uses super). It's also one less place you need to change code if/when you change what a class is inherited from (for example, you factor out a base-class and change the derivation and don't need to worry about your classes calling the wrong parent constructors). Also on the MI front, you only need one super call to correctly call all the base-class constructors.

Solution 2

You should explicitely call the superclass' init function:

class Employee(Person):
    def __init__(self):
        Person.__init__(self)
        self.empnum = "abc123"

Solution 3

Employee has to explicitly invoke the parent's __init__ (not init):

 class Employee(Person):  
    def __init__(self):  
         Person.__init__(self)  
         self.empnum = 'abc123'  

Solution 4

Instead of super(class, instance) pattern why not just use super(instance) as the class is always instance.__class__?

Are there specific cases where it would not be instance.__class__?

Share:
22,727
meade
Author by

meade

Happy on the outside, sad on the inside type of project manager

Updated on May 27, 2020

Comments

  • meade
    meade almost 4 years

    I'm playing with Python Class inheritance and ran into a problem where the inherited __init__ is not being executed if called from the sub-class (code below) the result I get from Active Python is:


    >>> start
    Tom Sneed
    Sue Ann
    Traceback (most recent call last):
      File "C:\Python26\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 312, <br>in RunScript
        exec codeObject in __main__.__dict__
      File "C:\temp\classtest.py", line 22, in <module>
        print y.get_emp()
      File "C:\temp\classtest.py", line 16, in get_emp
        return self.FirstName + ' ' + 'abc'
    AttributeError: Employee instance has no attribute 'FirstName'
    

    Here's the code

    class Person():
        AnotherName = 'Sue Ann'
        def __init__(self):
            self.FirstName = 'Tom'
            self.LastName = 'Sneed'
    
        def get_name(self):
            return self.FirstName + ' ' + self.LastName
    
    class Employee(Person):
        def __init__(self):
            self.empnum = 'abc123'
    
        def get_emp(self):
            print self.AnotherName
            return self.FirstName + ' ' + 'abc'
    
    x = Person()
    y = Employee()
    print 'start'
    print x.get_name()
    print y.get_emp()
    
  • Martin Geisler
    Martin Geisler almost 15 years
    Care must be taken when using super, please read this: fuhm.net/super-harmful
  • Jarret Hardie
    Jarret Hardie almost 15 years
    +1 for recommending new style classes, particularly as the OP's stack trace suggests they're using Python 2.6.
  • meade
    meade almost 15 years
    That worked - but why? why would the inherited class not work the same as if you instantiated it as its own object?
  • user1066101
    user1066101 almost 15 years
    No issue of the superclass has no init. It's pretty black-box-ish.
  • Martin Cote
    Martin Cote almost 15 years
    Python will not automatically call the superclass' init function when instantiating a subclass. This responsability is left to the programmer. I don't know if there's a rationale behind this.
  • workmad3
    workmad3 almost 15 years
    Good to know about the pitfalls. I've been pretty careful so far though and all my python code calls super() all the way back up to object :)
  • Samantha Atkis
    Samantha Atkis over 13 years
    wow. I think it erased part of my comment. it should be "instance.__class__" of course.
  • Veky
    Veky about 10 years
    This is actually an excellent question. Please watch pyvideo.org/video/879/the-art-of-subclassing (TL;DW: no, it's not instance.__class__. "self" is not neccessarily you.)