< BACKMake Note | BookmarkCONTINUE >
156135250194107072078175030179198180025031194137176049106218111004231203005073168108087143

Inheritance

Inheritance describes how the attributes of base classes are "bequeathed" to a derived class. A subclass inherits attributes of any of its base classes whether they be data attributes or methods.

We present an example below. P is a simple class with no attributes. C is a class with no attributes which derives from (and therefore is a subclass of) P:

					
>>> class P:                      # parent class
…       pass
>>> class C(P):                   # child class
…       pass
>>>
>>> c = C()                       # instantiate child
>>> c.__class__                   # child "is a" parent
<class __main__.C at 8120c98>
>>> C.__bases__                   # child's parent class(es)
(<class __main__.P at 811fc98>,)

				

Because P has no attributes, nothing was inherited by C. Let us make our example more useful by giving P some attributes:

					
>>> class P:                    # parent class
…      'P class'
…        def __init__(self):
…            print 'created an instance of', \
…                self.__class__.__name__
…
>>> class C(P):                 # child class
…        pass

				

We now create P with a documentation string (__doc__) and a constructor which will execute when we instantiate P, as in this interactive session:

					
>>> p = P()                      # parent instance
created an instance of P
>>> p.__class__                  # class that created us
<class __main__.P at 811f900>
>>> P.__bases__                  # parent's parent class(es)
()
>>> P.__doc__                    # parent's doc string
'P class'
>>> dir(P)                       # parent class attributes
['__doc__', '__init__', '__module__']

				

The "created an instance" output comes directly from __init__(). We also display some more about the parent class P for your information. Since P is not a subclass, its __bases__ attribute is empty. We will now instantiate C, showing you how the __init__() (constructor) method is inherited with its execution:

					
>>> c = C()                            # child instance
created an instance of C
>>> c.__class__                        # class that created us
<class __main__.C at 812c1b0>
>>> C.__bases__                        # child's parent class(es)
(<class __main__.P at 811f900>,)
>>> C.__doc__                          # child's doc string
>>>
>>> dir(C)                             # child class attributes
['__doc__', '__module__']

				

C has no declared method __init__(), yet there is still output when instance c of class C is created. The reason is that C inherits __init__() from P. The __bases__ tuple now lists P as its parent class.

You will notice that some special data attributes are not inherited, the most notable of which is __doc__. Each class should have its own documentation string. It does not make sense inheriting special class attributes because the values generally relate to one specific class.

__bases__ Class Attribute

We briefly introduced the __bases__ class attribute in Section 13.4.4, which is a tuple containing the set of parent classes for any (sub)class. Note that we specifically state "parents" as opposed to all base classes (which includes all ancestor classes). Classes which are not derived will have an empty __bases__ attribute. Let us look at an example of how to make use of __bases__.

						
>>> class A: pass                   # define class A
…
>>> class B(A): pass                # subclass of A
…
>>> class C(B): pass                # subclass of B (and indirectly, A)
…
>>> class D(A,B): pass              # subclass of A and B
…
>>> C.__bases__
(<class __main__.B at 8120c90>,)
>>> D.__bases__
(<class __main__.A at 811fc90>, <class __main__.B at 8120c90>)

					

In the example above, although C is a derived class of both A (through B) and B, C's parent is B, as indicated in its declaration, so only B will show up in C.__bases__. On the other hand, D inherits from two classes, A and B. (Multiple inheritance is covered in Section 13.10.4.)

Overriding Methods through Inheritance

Let us create another function in P that we will override in its child class:

						
>>> class P:
…        def foo(self):
…            print 'Hi, I am P-foo()'
…
>>> p = P()
>>> p.foo()
Hi, I am P-foo()

					

Now let us create the child class C, subclassed from parent P:

						
>> class C(P):
…        def foo(self):
…            print 'Hi, I am C-foo()'
…
>>> c = C()
>>> c.foo()
Hi, I am C-foo()

					

Although C inherits P's foo() method, it is overridden because C defines its own foo() method. One reason for overriding methods is because you may want special or different functionality in your subclass. Your next obvious question then must be, "Can I call a base class method which I overrode in my subclass?"

The answer is yes, but this is where you will have to invoke an unbound base class method, explicitly providing the instance of the subclass, as we do here:

						
>>> P.foo(c)
Hi, I am P-foo()

					

Notice that we already had an instance of P called p from above, but that is nowhere to be found in this example. We do not need an instance of P to call a method of P because we have an instance of a subclass of P which we can use, c.

NOTE

When deriving a class with a constructor __init__(), if you do not override __init__(), it will be inherited and automatically invoked. But if you do override __init__() in a subclass, the base class __init__() method is not invoked automatically when the subclass is instantiated.

							
>>> class P:
…        def __init__(self):
…            print "calling P\xd5 s constructor"
…
>>> class C(P):
…        def __init__(self):
…            print "calling C\xd5 s constructor"
…
>>> c = C()
created an instance of C

						

If you want the base class __init__() invoked, you need to do that explicitly in the same manner as we just described, calling the base class (unbound) method with an instance of the subclass. Updating our class C appropriately results in the following desired execution:

							
>>> class C(P):
…        def __init__(self):
…            P.__init__(self)
…            print "calling C's constructor"
…
>>> c = C()
calling P's constructor
calling C's constructor

						

In the above example, we call the base class __init__() method before the rest of the code in our own __init__() method. It is fairly common practice (if not mandatory) to initialize base classes for setup purposes, then proceed with any local setup. This rule makes sense because you want the inherited object properly initialized and "ready" by the time the code for the derived class constructor runs, because it may require or set inherited attributes.

Those of you familiar with C++ would call base class constructors in a derived class constructor declaration by appending a colon to the declaration followed by calls to any base class constructors. Java programmers have no choice—base class constructors must always be called as the first thing that happens in derived class constructors. Python's use of the base class name to invoke a base class method is directly comparable to Java's when using the keyword super.


Deriving Standard Types

One limitation is that Python types are not classes, meaning that we cannot derive subclasses from them. Not all is lost though, because of the many different special default attribute methods we can implement to emulate the standard types (see the Core Note in Section 4.2 as well as Sections 6.14.2 and 13.12).

Multiple Inheritance

Python allows for subclassing from multiple base classes. This feature is commonly known as "multiple inheritance." Python supports a limited form of multiple inheritance whereby a depth-first searching algorithm is employed to collect the attributes to assign to the derived class. Unlike other Python algorithms which override names as they are found, multiple inheritance takes the first name that is found.

Our example below consists of a pair of parent classes, a pair of children classes, and one grandchild class.

						
class P1:                         # parent class 1
   def foo(self):
      print 'called P1-foo()'

class P2:                         # parent class 2
   def foo(self):
      print 'called P2-foo()'
   def bar(self):
      print 'called P2-bar()'

class C1(P1,P2):                  # child 1 der. from P1, P2
   pass

class C2(P1,P2):                  # child 2 der. from P1, P2
   def foo(self):
      print 'called C2-foo()'
   def bar(self):
      print 'called C2-bar()'

class GC(C1,C2):                  # define grandchild class
   pass                           # derived from C1 and C2

					

Upon executing the above declarations in the interactive interpreter, we can confirm that only the first attributes encountered are used.

						
>> gc = GC()
>>> gc.foo()       # GC ? C1 ? P1
called P1-foo()
>>> gc.bar()       # GC ? C1 ? P1 ? P2
called P2-bar()

					

Again, you can always call a specific method by invoking the method using its fully-qualified name and providing a valid instance:

						
>>> C2.foo(gc)
called C2-foo()

					


Last updated on 9/14/2001
Core Python Programming, © 2002 Prentice Hall PTR

< BACKMake Note | BookmarkCONTINUE >

© 2002, O'Reilly & Associates, Inc.