chenchiyuan
chenchiyuan

Reputation: 151

Confusing python inheritance


class BaseA(object):
    authors = ['a', 'b']
    author_list = authors

class BaseB(object):
    authors = ['a', 'b']

    def __init__(self, *arg, **kwargs):
        self.author_list = self.authors

class ChildA(BaseA):
    authors = ['c', 'd']

class ChildB(BaseB):
    authors = ['c', 'd']

child_a = ChildA()
child_b = ChildB()
print(child_a.author_list)
print(child_b.author_list)
>>> ['a', 'b']
>>> ['c', 'd']

What's the different of the codes? Why do I get different results?

I'm so confusing why parent author_list attributes don't be override.

Can you tell me the principle of python inheritance?

Upvotes: 1

Views: 220

Answers (4)

mOmOney
mOmOney

Reputation: 373

Recommended way to write your Python code:

class BaseA(object):
    def __init__(self):
        self.authors = ['a', 'b']

class BaseB(object):
    def __init__(self):
        self.authors = ['a', 'b']

class ChildA(BaseA):
    def __init__(self):
        self.authors = ['c', 'd']
    
class ChildB(BaseB):
    def __init__(self):
        self.authors = ['c', 'd']


child_a = ChildA()
child_b = ChildB()
print(child_a.authors)
print(child_b.authors)
>>> ['c', 'd']
>>> ['c', 'd']

Recommended ways to call the Superclass (Base Parent class):

class BaseA(object):
    def __init__(self):
        self.authors = ['a', 'b']

class BaseB(object):
    def __init__(self):
        self.authors = ['a', 'b']

class ChildA(BaseA):
    def __init__(self):
        self.authors = ['c', 'd']
        super().__init__()
    
class ChildB(BaseB):
    def __init__(self):
        self.authors = ['c', 'd']
        BaseB.__init__(self)


child_a = ChildA()
child_b = ChildB()
print(child_a.authors)
print(child_b.authors)
>>> ['a', 'b']
>>> ['a', 'b']

Esoteric superclass call using one underscore at the end of __init__ (__init_):

class BaseA(object):
    def __init__(self):
        self.authors = ['a', 'b']

class BaseB(object):
    def __init__(self):
        self.authors = ['a', 'b']

class ChildA(BaseA):
    def __init_(self):
        self.authors = ['c', 'd']
    
class ChildB(BaseB):
    def __init_(self):
        self.authors = ['c', 'd']


child_a = ChildA()
child_b = ChildB()
print(child_a.authors)
print(child_b.authors)
>>> ['a', 'b']
>>> ['a', 'b']

CAUTION

Using esoteric superclass call results in losing all access to children variables!

Access to methods in the subclass (Child class) will still be accessible, but all access to variables in the subclass (Child class) will be lost completely.

Upvotes: 0

mOmOney
mOmOney

Reputation: 373

In your BaseB __init__ function you are calling the Child's authors, not the Parent's authors. If you wish to call the Parent's authors you would use BaseB.authors instead of self.authors:

class BaseA(object):
    authors = ['a', 'b']
    author_list = authors

class BaseB(object):
    authors = ['a', 'b']

    def __init__(self, *arg, **kwargs):
        self.author_list = BaseB.authors

class ChildA(BaseA):
    authors = ['c', 'd']

class ChildB(BaseB):
    authors = ['c', 'd']

child_a = ChildA()
child_b = ChildB()
print(child_a.author_list)
print(child_b.author_list)
>>> ['a', 'b']
>>> ['a', 'b']

In the case where you would be concatenating the authors of the ParentB and the ChildB then you would use both BaseB.authors and self.authors:

class BaseA(object):
    authors = ['a', 'b']
    author_list = authors

class BaseB(object):
    authors = ['a', 'b']

    def __init__(self, *arg, **kwargs):
        self.author_list = BaseB.authors + self.authors

class ChildA(BaseA):
    authors = ['c', 'd']

class ChildB(BaseB):
    authors = ['c', 'd']

child_a = ChildA()
child_b = ChildB()
print(child_a.author_list)
print(child_b.author_list)
>>> ['a', 'b']
>>> ['a', 'b', 'c', 'd']

Override

class BaseA(object):
    authors = ['a', 'b']
    author_list = authors

class BaseB(object):
    authors = ['a', 'b']

    def __init__(self, *arg, **kwargs):
        self.author_list = self.authors

class ChildA(BaseA):
    authors = ['c', 'd']
    def __init__(self, *arg, **kwargs):
        self.author_list = self.authors

class ChildB(BaseB):
    authors = ['c', 'd']

child_a = ChildA()
child_b = ChildB()
print(child_a.author_list)
print(child_b.author_list)
>>> ['c', 'd']
>>> ['c', 'd']

Upvotes: 0

BrenBarn
BrenBarn

Reputation: 251558

Material inside the class block is part of the class itself, and is executed once, when you define the class. Material in __init__ is per-instance, and is executed once per instance, every time you instantiate the class.

In your first example (BaseA), you create a class attribute authors, then create another attribute author_list pointing to the same value. That is it. Nothing else ever happens. The fact that ChildA inherits from BaseA does not cause author_list = authors to be re-executed. author_list was over and done with once BaseA was defined.

In your second example (BaseB), you create a class attribute authors. Then in __init__ you make a new instance attribute pointing at that same value. Since you do this in __init__, it is re-done for each instance. So when you instantiate BaseB, it gets the new attribute.

Note that you are checking the attributes on the instances child_a and child_b. If you check them on the classes (ChildA.author_list and ChildB.author_list), you will see that both have the same value (['a', 'b']). Because your action in ChildB takes place in __init__, it only takes effect when you actually instantiate the class.

Upvotes: 4

coredump
coredump

Reputation: 3107

The difference is that in the second example, author_list is set when you create an instance of an object.

When you define class BaseA you define the class member author_list and that's that, so when you create an instance of ChildA nothing is happening to author_list. It is just inherited.

When you define BaseB there is no member author_list. That is created as a instance variable when an instance of BaseB is created. So, when you create an instance of ChildB the same thing happens, but since authors is redefined then it will use the new value of authors

Upvotes: 0

Related Questions