3

I did some test today:

class SuperC():
    def __init__(self, a, b, c, d='D0'):
        self.A = a
        self.B = b
        self.C = c
        self.D = d
        self.E = 'E0'

sup = SuperC('A0', 'B0', 'C0')
print(sup.A)  # >>> A0
print(sup.B)  # >>> B0
print(sup.C)  # >>> C0
print(sup.D)  # >>> D0
print(sup.E)  # >>> E0

you can see in the superclass, there are two types of default value (d and e) d is more 'open', while e is kind of 'hidden'

Now, if I create a subclass, with a new attribute 'f':

class SubC1(SuperC):
    def __init__(self, a, b, c, f):
        super().__init__(a, b, c)
        self.F = f

sub1 = SubC1('A1', 'B1', 'C1', 'F1')
print(sub1.A)  # >>> A1 
print(sub1.B)  # >>> B1
print(sub1.C)  # >>> C1
print(sub1.D)  # >>> D0
print(sub1.E)  # >>> E0  
print(sub1.F)  # >>> F1   

I can see that a,b,c got good inheritance, and can accept new values. But I did not choose to have d and e in super().__init__(). BUT they got perfect inheritance as well, and the problem is that I can not change the value of d and e while creating the instance of the subclass. and f works fine.

Now I create another subclass:

class SubC2(SuperC):
        def __init__(self, a, b, c, f, d='D2'): 
            super().__init__(a, b, c, d)  
            self.F = f

sub2 = SubC2('A2', 'B2', 'C2', 'F2')
print(sub2.A)  # >>> A2
print(sub2.B)  # >>> B2
print(sub2.C)  # >>> C2
print(sub2.D)  # >>> D2     
print(sub2.E)  # >>> E0  # hidden e is still E0
print(sub2.F)  # >>> F2

with d written in both __init__() and super().__init__(), now that d can get perfect inheritance and can be overwritten with new default value or new value in an new instance. but e will still be E0

It seems like the only good way is:

class SubC3(SuperC):
    def __init__(self, a, b, c, f, d='new D', e='new E'):
        super().__init__(a, b, c)
        self.D = d  # set new
        self.E = e  # set new
        self.F = f

sub3 = SubC3('A3', 'B3', 'C3', 'F3')
print(sub3.A)  # >>> A3
print(sub3.B)  # >>> B3
print(sub3.C)  # >>> C3
print(sub3.D)  # >>> new D
print(sub3.E)  # >>> new E
print(sub3.F)  # >>> F3

Now that I can have both d and e with brand new default value/instance value, but if left non-indicated, then they will not inherit from the SuperC

My question is, am I thinking this the right way? Did I miss anything? Are there better ways to set default value inheritance?

Or maybe in a way, that e is not supposed to be changed if written in this way? because it could be a fundamental attribute that is supposed to be a constant value for both superclass and subclass?

1
  • 1
    This question ought probably be closed as entirely opinion based. There is no "right" or "best" way to do this. There's nothing "wrong" with any of your example classes. Which you use just boils down to how you want to interact with your class. Commented Dec 31, 2017 at 3:56

1 Answer 1

3

I seem to fail the understand the issue...

When you do this:

class SuperC():
    def __init__(self, a, b, c, d='D0'):
        self.A = a
        self.B = b
        self.C = c
        self.D = d
        self.E = 'E0'

self.E is not "hidden". It just received a hardcoded value: the string "E0" and d='D0' can be read as If you're called with an specific value in the d argument, use that one, otherwise, just use the string "D0" (it's a named optional argument)

When you do this:

class SubC3(SuperC):
    def __init__(self, a, b, c, f, d='new D', e='new E'):
        super().__init__(a, b, c)
        self.D = d  # set new
        self.E = e  # set new
        self.F = f

What's happening is that the call to super().__init__ creates a class with whatever a, b, c arguments you passed, a self.E and the hardcoded "E0". After that, you do self.E = e and then you overwrite that "E0" with the value of the argument e.

Try this:

class SubC3(SuperC):
    def __init__(self, a, b, c, f, d='new D', e='new E'):
        super().__init__(a, b, c)
        print("Before overwrite=%s" % self.E)
        self.D = d  # set new
        self.E = e  # set new
        print("After overwrite=%s" % self.E)
        self.F = f

sub3 = SubC3('A3', 'B3', 'C3', 'F3')

You'll see that right after the init, you see self.E being "E0" and then it's overwritten:

Before overwrite=E0
After overwrite=new E

About the d:

Try this:

class SubC3(SuperC):
    def __init__(self, a, b, c, f, d='new D', e='new E'):
        super().__init__(a, b, c)
        self.E = e  # set new
        self.F = f

sub3 = SubC3('A3', 'B3', 'C3', 'F3')
print(sub3.D)

You'll see that it's D0, because you didn't pass any d to the super and you didn't overwrite it in SubC3.__init__, so it used the default in the SuperC.__init__ (where you do d='D0')

Sign up to request clarification or add additional context in comments.

3 Comments

I understand what you said and how d and e got passed. I am actually asking, what is the best way to pass the attributes from superclass to subclass, if a default value was given in the superclass.
You mean what to do with the d=... since they're both defined in SubC3 and SuperC?
I feel like there's no canonical way... To me, it all depends on the actual structure, and what feels natural. If you have a base class that you wanna subclass, and in some subclasses you think you need an argument, but in other subclasses you won't need it, then a kwarg (the d="D0") works fine. Otherwise, if all your subclasses are going to need the argument, then don't make it optional... I'd say it depends on your actual scenario.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.