Each Answer to this Q is separated by one/two green lines.
There seems to be no good online documentation on this:
If I make a derived class, will it automatically have all the attributes of the base class? But what’s the
BaseClass.__init() for, do you also need to do it to other base class methods? Does
BaseClass.__init__() need arguments? If you have arguments for your base class
__init__(), are they also used by the derived class, do you need to explicitly set the arguments to the derived classe’s
__init__(), or set them to
If you implement
__init__ in a class derived from BaseClass, then it will overwrite the inherited
__init__ method and so
BaseClass.__init__ will never be called. If you need to call the
__init__ method for BaseClass (as is normally the case), then its up to you to do that, and its done explicitly by calling
BaseClass.__init__, normally from within the newly implemented
class Foo(object): def __init__(self): self.a = 10 def do_something(self): print self.a class Bar(Foo): def __init__(self): self.b = 20 bar = Bar() bar.do_something()
This will cause the following error:
AttributeError: 'Bar' object has no attribute 'a'
do_something method has been inherited as expected, but that method requires the attribute
a to have been set, which it never is because
__init__ was also overwritten. We get round this by explicitly calling
Foo.__init__ from within
class Foo(object): def __init__(self): self.a = 10 def do_something(self): print self.a class Bar(Foo): def __init__(self): Foo.__init__(self) self.b = 20 bar = Bar() bar.do_something()
10 as expected.
Foo.__init__ in this case expects a single argument which is an instance of
Foo (which by convention is called
Normally, when you call a method on an instance of a class, the class instance is passed automatically as the first argument. Methods on an instance of a class are called bound methods.
bar.do_something is an example of a bound method (and you’ll note that it is called without any arguments).
Foo.__init__ is an unbound method because it is not attached to a particular instance of
Foo, so the first argument, an instance of
Foo, needs to be passed explicitly.
In our case, we pass
Foo.__init__, which is the instance of
Bar that was passed to the
__init__ method in
Bar inherits from
Foo, instances of
Bar are also instances of
Foo, so passing
Foo.__init__ is allowed.
It is likely be the case that the class you are inheriting from requires or accepts more arguments than just an instance of the class. These are dealt with as you would with any method you’re calling from within
class Foo(object): def __init__(self, a=10): self.a = a def do_something(self): print self.a class Bar(Foo): def __init__(self): Foo.__init__(self, 20) bar = Bar() bar.do_something()
which would print
If you’re trying to implement a interface that fully exposes all the initialisation arguments of the base class through your inheriting class, you’ll need to do so explicitly. This is typically done with the *args and **kwargs arguments (the names are by convention), which are placeholders for all rest of the arguments that aren’t explicitly named. The following example makes use of everything I’ve discussed:
class Foo(object): def __init__(self, a, b=10): self.num = a * b def do_something(self): print self.num class Bar(Foo): def __init__(self, c=20, *args, **kwargs): Foo.__init__(self, *args, **kwargs) self.c = c def do_something(self): Foo.do_something(self) print self.c bar = Bar(40, a=15) bar.do_something()
In this case, the argument
c is set to be 40, as it’s the first argument to
Bar.__init__. The second argument is then incorporated into the variables
kwargs (the * and ** is specific syntax that says expand the list/tuple or dictionary into separate arguments when passing to a function/method), and is passed on to
This example also makes the point that any overwritten method needs to be called explicitly if that is what is required (as
do_something is in this case).
One final point, you will often see
super(ChildClass, self).method() (where
ChildClass is some arbitrary child class) being used instead of a call to the
BaseClass method explicitly. Discussion of
super is a whole other question, but suffice it to say, in these cases it’s typically being used to do exactly what is being done by calling
super delegates the method call to the next class in the method resolution order – the MRO (which in single inheritance is the parent class). See the documentation on super for more info.
If I make a derived class, will it automatically have all the attributes of the base class?
Class attributes, yes. Instance attributes, no (simply because they don’t exist when the class is created), unless there’s no
__init__ in the derived class, in which case the base one will be called instead, and will set the instance attributes.
Does BaseClass.init() need arguments?
Depends on the class and its
__init__ signature. If you’re explicitly calling
Base.__init__ in the derived class, you will at least need to pass
self as the first argument. If you have
class Base(object): def __init__(self): # something
then it’s rather obvious that no other arguments are accepted by the
__init__. If you’d have
class Base(object): def __init__(self, argument): # something
then you have to pass
argument when calling base
__init__. No rocket science in here.
If you have arguments for your base class init(), are they also used by the derived class, do you need to explicitly set the arguments to the derived classe’s init(), or set them to BaseClass.init() instead?
Again, if the derived class doesn’t have
__init__, base one will be used instead.
class Base(object): def __init__(self, foo): print 'Base' class Derived(Base): pass Derived() # TypeError Derived(42) # prints Base
In other case, you need to take care of it somehow. Whether you use
*args, **kwargs and just pass arguments unmodified to the base class, or copy the base class signature, or supply arguments from elsewhere, depends on what you’re trying to accomplish.