How to Initialize the Base (Super) Class

How do I initialize the base (super) class?

Python (until version 3) supports "old-style" and new-style classes. New-style classes are derived from object and are what you are using, and invoke their base class through super(), e.g.

class X(object):
def __init__(self, x):
pass

def doit(self, bar):
pass

class Y(X):
def __init__(self):
super(Y, self).__init__(123)

def doit(self, foo):
return super(Y, self).doit(foo)

Because python knows about old- and new-style classes, there are different ways to invoke a base method, which is why you've found multiple ways of doing so.

For completeness sake, old-style classes call base methods explicitly using the base class, i.e.

def doit(self, foo):
return X.doit(self, foo)

But since you shouldn't be using old-style anymore, I wouldn't care about this too much.

Python 3 only knows about new-style classes (no matter if you derive from object or not).

Initializing superclasses Python3

In general, if you override __init__ in your subclass, you should call the super __init__ method only. This is necessary if you extend the superclass. But if you want to overwrite the whole __init__, you can also omit the super call.

Example:

You have class A that has one attribute value1.
And now you need a second attribute, so you subclass A with B and overwrite the __init__ where you call the super class (A), so A can set value1 and in B you can not set value2.

But now you need some other attributes in C, but need the same methods as in A. So you can entirely overwrite __init__ and omit the super call to A.

class A:
def __init__(self, value1):
print("Initialize A")
self.value1 = value1

class B(A):
def __init__(self, value1, value2):
super().__init__(value1)
print("Initialize B")
self.value2 = value2

class C(A):
def __init__(self, value3):
print("Initialize C")
self.value3 = value3

a = A("foo")
b = B("foo", "bar")
c = C("baz")

print(a.value1)
print(b.value1, b.value2)
print(c.value3)
print(c.value1)

Output

$ python main.py
Initialize A
Initialize A
Initialize B
Initialize C
foo
foo bar
baz
Traceback (most recent call last):
File "main.py", line 27, in <module>
print(c.value1)
AttributeError: 'C' object has no attribute 'value1'

You can see C wasn't initialized with value1, because C didn't call A's __init__.

What are the rules for calling the base class constructor?

Base class constructors are automatically called for you if they have no argument. If you want to call a superclass constructor with an argument, you must use the subclass's constructor initialization list. Unlike Java, C++ supports multiple inheritance (for better or worse), so the base class must be referred to by name, rather than "super()".

class SuperClass
{
public:

SuperClass(int foo)
{
// do something with foo
}
};

class SubClass : public SuperClass
{
public:

SubClass(int foo, int bar)
: SuperClass(foo) // Call the superclass constructor in the subclass' initialization list.
{
// do something with bar
}
};

More info on the constructor's initialization list here and here.

Does a subclass need to initialize an empty super class?

This is just fine:

class Parent:
# the __init__ is inherited from parent
pass

class Child(Parent):
# the __init__ is inherited from parent
pass

This is also fine:

class Parent:
# the __init__ is inherited from parent
pass

class Child(Parent):
def __init__(self):
# __init__ is called on parent
super().__init__()

This may seem ok, and will usually work fine, but not always:

class Parent:
# the __init__ is inherited from parent
pass

class Child(Parent):
def __init__(self):
# this does not call parent's __init__,
pass

Here is one example where it goes wrong:

class Parent2:
def __init__(self):
super().__init__()
print('Parent2 initialized')

class Child2(Child, Parent2):
pass

# you'd expect this to call Parent2.__init__, but it won't:
Child2()

This is because the MRO of Child2 is: Child2 -> Child -> Parent -> Parent2 -> object.

Child2.__init__ is inherited from Child and that one does not call Parent2.__init__, because of the missing call to super().__init__.

Understanding Python super() with __init__() methods

super() lets you avoid referring to the base class explicitly, which can be nice. But the main advantage comes with multiple inheritance, where all sorts of fun stuff can happen. See the standard docs on super if you haven't already.

Note that the syntax changed in Python 3.0: you can just say super().__init__() instead of super(ChildB, self).__init__() which IMO is quite a bit nicer. The standard docs also refer to a guide to using super() which is quite explanatory.

Initialization of a base class reference from a derived class member

The base class Base of Derived is constructed before the member data.

As a result data will not be initialized when you pass a reference to it to Base's constructor. The initialization will happen after that constructor call.

You are however trying to read the member x of data in Base's constructor. At this point data's lifetime has not started yet and accessing the value of a non-static data member of an object outside its lifetime causes undefined behavior.

Whether or not the assertions succeed isn't significant. Undefined behavior allows for either outcome.

The situation would be potentially different (although technically not rules in the standard) if you were not trying to access the value of data inside Base's constructor, but only storing the reference to it.

How to initialize inherited class with base class?

You can create a constructor in your derived class and map the objects,

public class MyInheritedClass : MyClass
{
MyInheritedClass (MyClass baseObject)
{
this.UserName = baseObject.UserName; // Do it similarly for rest of the properties
}
public string Email { get; set; }
}

MyInheritedClass inheritedClassObject = new MyInheritedClass(myClassObject);
inheritedClassObject.GetJson();

Updated Constructor :

        MyInheritedClass (MyClass baseObject)
{
//Get the list of properties available in base class
var properties = baseObject.GetProperties();

properties.ToList().ForEach(property =>
{
//Check whether that property is present in derived class
var isPresent = this.GetType().GetProperty(property);
if (isPresent != null && property.CanWrite)
{
//If present get the value and map it
var value = baseObject.GetType().GetProperty(property).GetValue(baseObject, null);
this.GetType().GetProperty(property).SetValue(this, value, null);
}
});
}


Related Topics



Leave a reply



Submit