JLagana
JLagana

Reputation: 1294

How to make child class use parent's default values?

I have a parent class:

class BaseClass:
    def __init__(self, foo, bar=10):
        self.foo = foo  

And an inherited class from it:

class InheritedClass(BaseClass):
    def __init__(self, x, y, bar=10):
        super().__init__(True, bar=bar)
        self.x = x
        self.y = y

At the moment, bar has a default value in both the parent and the inherited class, which I have to keep track of to make sure they are both synced. How can I change the InheritedClass constructor to instead use the default value for bar defined in the BaseClass?


I've tried:

class InheritedClass(BaseClass):
    def __init__(self, x, y, bar=None):
        if bar is None:
            super().__init__(True)
        else:
            super().__init__(True,bar)
        self.x = x
        self.y = y

which provides the behavior I'm looking for, but doesn't seem very scalable. Is there a better way?

Upvotes: 2

Views: 1180

Answers (3)

chepner
chepner

Reputation: 531165

Don't expose the parent's arguments at all in the signature; just pass what you receive on (if anything) on to the next class in the MRO.

class BaseClass:
    def __init__(self, foo, bar=10, **kwargs):
        super().__init__(**kwargs)
        # Do something with bar
        self.foo = foo


class InheritedClass(BaseClass):
    def __init__(self, x, y, **kwargs)
        kwargs['foo'] = True
        super().__init__(**kwargs)
        self.x = x
        self.y = y

You have to accept and pass on arbitrary keywords anyway to use super properly, so you may as well do the same thing for the parent class's arguments, even though you "know" them already.

This also means always using keyword arguments for __init__, as you can't really predict how your class's positional arguments will interact with another class on the MRO. (Positional arguments can only be consumed on a first-come, first-served basis, and you simply don't know in the case of multiple inheritance when your class's method will be called.)

foo = InheritedClass(bar=9, x=3, y=10)

Upvotes: 2

Saad
Saad

Reputation: 3430

Your approach is not bad and yes there is a better way to do it maybe better than mine but here is what I come up with hope this helps.

Sample:

class BaseClass:
    def __init__(self, foo, bar=10):
        self.foo = foo 
        self.bar = bar 

class InheritedClass(BaseClass):
    def __init__(self, x, y, bar=None):
        super().__init__(True, bar=bar)
        if bar is None: bar = self.bar
        self.x = x
        self.y = y

Upvotes: 0

blhsing
blhsing

Reputation: 106553

You can use variable arguments instead:

class InheritedClass(BaseClass):
    def __init__(self, x, y, *args, **kwargs):
        super().__init__(True, *args, **kwargs)
        self.x = x
        self.y = y

Upvotes: 1

Related Questions