Lucas
Lucas

Reputation: 23

Python class inheritance and sharing variables

I have a question about accessing a variable between two classes, where one is the base class. I have a program which I'm writing where there's a single 'settings' variable and it's shared between several classes. This is a simplistic version of it.

This code snippet works. When I run it, I can access run() from the Top class, and both classes have access to self.settings, and when I print it out from go(), it contains both 'a' and 'b' keys.

The problem is, pylint and my IDE say "Instance of 'Base' has no 'settings' member". Which I understand is because it's not initialized in Base.init().

class Base:
    def __init__(self):
        self.settings["b"] = False

    def run(self):
        print("RUN")


class Top(Base):
    def __init__(self):
        self.settings = dict(a=True)
        Base.__init__(self)

    def go(self):
        print(self.settings)


x = Top()
x.go()
x.run()

This is a slightly modified version, where I am passing 'self' from Top twice to Base, and using 'main.settings' instead of self.settings. Pylint nor my IDE complain about this. I'm clearly passing the self instance into it to share, so I understand that.

class Base:
    def __init__(self, main):
        main.settings["b"] = False

    def run(self):
        print("RUN")


class Top(Base):
    def __init__(self):
        self.settings = dict(a=True)
        Base.__init__(self, self)

    def go(self):
        print(self.settings)


x = Top()
x.go()
x.run()

What I don't understand, is what is the proper way to achieve this? The other option of course is to pass the settings variable itself. However I have several variables and possibly methods which need to be used by both classes, so passing 'self' seems like the best option.

Upvotes: 1

Views: 786

Answers (3)

Samwise
Samwise

Reputation: 71424

Init settings in Base, not Top.

class Base:
    def __init__(self):
        self.settings = {}
        self.settings["b"] = False

    def run(self):
        print("RUN")


class Top(Base):
    def __init__(self):
        Base.__init__(self)
        self.settings["a"] = True

    def go(self):
        print(self.settings)

Child classes should depend on their parent classes, not vice versa. If Base doesn't init self.settings, then it depends on some other as-yet-undefined class to init it (which is a bad dependency/assumption to introduce).

Upvotes: 1

Wizard.Ritvik
Wizard.Ritvik

Reputation: 11612

I would pass in **kwargs, so it's easy to keep insertion order the same as you had it:

class Base:
    def __init__(self, **kwargs):
        self.settings = {**kwargs, 'b': False}

    def run(self):
        print("RUN")


class Top(Base):
    def __init__(self):
        super().__init__(a=True)

    def go(self):
        print(self.settings)


x = Top()
x.go()
x.run()

Output:

{'a': True, 'b': False}
RUN

Upvotes: 0

Barmar
Barmar

Reputation: 780698

You should create self.settings in the base class, not the child. Then the child can add its key to it after calling the base's __init__() method.

class Base:
    def __init__(self):
        self.settings = {"b": False}

    def run(self):
        print("RUN")


class Top(Base):
    def __init__(self):
        super().__init__()
        self.settings['a'] = True

    def go(self):
        print(self.settings)


x = Top()
x.go()
x.run()

Upvotes: 1

Related Questions