Python class inheritance and sharing variables - python

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.

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).

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()

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

Related

reference instance attribute in child class

I am trying to call an instance variable from a "parent" class (subclass) to it's "child" class (subsubclass)
class mainclass():
def __init__(self):
self.mainclassvar1 = "mainclass"
class subclass(mainclass):
def __init__(self):
self.subclassvar1 = "subclass"
def changeval(self):
self.subclassvar1 = "subclassedited"
class subsubclass(subclass):
def __init__(self):
self.subsubclassvar1 = subclass.subclassvar1 #<- naturally this fails
def handler():
main=mainclass()
sub = subclass()
sub.changeval()
subsub = subsubclass()
print(subsub.subsubclassvar1)# <- how do I achieve this? I would expect "subclassedited" but it doesn't
if __name__ == "__main__":
handler()
The above does not work obviously but I am trying to show what I am trying to achieve in my head.
if I change the class subsubclass(subclass) as follows it semi-works:
class subsubclass(subclass):
def __init__(self):
subclass.__init__(self)
self.subsubclassvar1 = self.subclassvar1
however the returned value is the original default value of subclass instead of the expected subclassedited.
I am not sure if I should even be trying to do this but I've got some code where the logic has now come to this point and I want to try see if I can get details from the middle class in to the final child class in their final modified states instead of the defaults and without refactoring a lot of code.
Each __init__ method should be invoking the parent's __init__ method, so that the instance is properly initialized for all the classes in the hierarchy.
class mainclass:
def __init__(self):
super().__init__()
self.mainclassvar1 = "mainclass"
class subclass(mainclass):
def __init__(self):
super().__init__()
self.subclassvar1 = "subclass"
def changeval(self):
self.subclassvar1 = "subclassedited"
class subsubclass(subclass):
def __init__(self):
super().__init__()
# Not sure why you would really need this, but...
self.subsubclassvar1 = self.subclassvar1
There's no reason, though that subsub.subclassvar1 should be related to sub.subclassvar1, though. Calling sub.changeval() has nothing to do with subsub.

How to override a function in an inheritance hierarchy?

I would like to implement a widget system similar to FLTK using python in a 3D world.
I simplified my code to the following. I don't get the correct answer. The function is not overwritten even if I change the variable.
def callbacks():
print("callback")
def create():
print ("override")
def default():
print("default")
class f1(object):
def __init__(self):
self.test=default
pass
def docallback(self):
self.test()
class f2(f1):
def __init__(self):
self.test=create
super().__init__()
class f3(f2):
def __init__(self):
self.test=callbacks
super().__init__()
t1=f1()
t2=f2()
t3=f3()
t1.docallback()
t2.docallback()
t3.docallback()
You should be calling super().__init__() first in this case:
class f1(object):
def __init__(self):
self.test = default
def docallback(self):
self.test()
class f2(f1):
def __init__(self):
super().__init__()
self.test = create
class f3(f2):
def __init__(self):
super().__init__()
self.test = callbacks
These 'constructors' call super().__init__() first (which makes assignments to self.test), but then immediately assigns the correct value to self.test itself.
f1.__init__ should use default as the default value of a parameter, not a hard-coded assignment.
class f1:
def __init__(self, test=default):
self.test = test
Then f2 and f3 can simply provide different arguments when using super().
class f2:
def __init__(self):
super().__init__(create)
class f3:
def __init__(self):
super().__init__(callbacks)

Why my child class not working fine for multiple parent class?

class Car(object):
condition = "new"
def __init__(self):
self.model =raw_input()
self.color = raw_input()
self.mpg = raw_input()
class Jeep(object):
condition = "new"
def __init__(self):
self.model =raw_input()
self.color = raw_input()
self.mpg = raw_input()
class ElectricCar(Car, Jeep):
def __init__(self, battery_type):
self.battery_type=battery_type
super(ElectricCar, self).__init__()
def printer(self):
print self.model
car = ElectricCar('battery')
car.printer()
print car.__dict__
Only 3 times I am getting to enter my entries instead of 6 plus I am confused how to avoid ambiguity as model is in car as well as jeep. How do I tackle them?
There are two problems here:
Python objects have one dict for storing attributes, there can be no attribute hiding like in other programming languages
You are incorrectly using multiple inheritance and super.
Python will not work how you want it to work. Each instance in Python has one shared dict which all classes share for attribute access. This means you cannot hide an attribute, only overwrite it. To do what you want you must a unique name for model in Car and a unique name in Jeep. eg. car_model and jeep_model. A quick test that shows this:
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
self.value = "parent"
def parent_value(self):
return self.value
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
self.value = "child"
def child_value(self):
return self.value
p = Parent()
assert p.parent_value() == "parent"
c = Child()
assert c.child_value() == "child"
assert c.parent_value() == "child"
You could use "private" variables. These aren't really private, python just does something called name mangling to make them harder to accidentally overwrite.
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
self.__value = "parent"
def parent_value(self):
return self.__value
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
self.__value = "child"
def child_value(self):
return self.__value
p = Parent()
assert p.parent_value() == "parent"
c = Child()
assert c.child_value() == "child"
assert c.parent_value() == "parent"
print(vars(c))
# prints {'_Child__value': 'child', '_Parent__value': 'parent'}
c._Parent__value = "new value"
assert c.parent_value() == "new value"
Finally, your __init__ methods in your base classes do not make a call to super. In non-multiple inheritance this is not necessary for the base class. However, in your case (which uses multiple inheritance) the set of __init__ methods will get to Car.__init__ and then stop without calling Jeep.__init__.
class Car(object):
def __init__(self):
print("init car")
super(Car, self).__init__()
print("assigning car")
self.car = "car"
class Jeep(object):
def __init__(self):
print("init jeep")
super(Jeep, self).__init__()
print("assigning jeep")
self.jeep = "jeep"
class ElectricCar(Car, Jeep):
def __init__(self):
print("init electric car")
super(ElectricCar, self).__init__()
print("assigning electric")
self.electric = "electric"
car = ElectricCar()
# prints the following:
# init electric car
# init car
# init jeep
# assigning jeep
# assigning car
# assigning electric

Python: sharing variables between contained class

Is there a way to share member variables between a class and a nested class ?
for example
class Base(object):
class __Internal(object):
def __init__(self, parent):
self.__parent = parent
self.__parent.__private_method()
#
def __init__(self):
self.__internal = Base.__Internal(self)
return
def __private_method(self):
print "hurray"
return
if name == "main":
b = Base()`
is there a way for the __Internal class to access members of the parent class ?
iam looking for private members like parent.__vars/__methods .
I have edited the code to better explain this. running this code throws
AttributeError: 'Base' object has no attribute '_Internal__private_method'
To access privete method, instead of this:
self.__parent.__private_method()
use this:
self.__parent._Base__private_method()
Modified your example:
class Base(object):
class __Internal(object):
def __init__(self, parent):
self.__parent = parent
self.__parent._Base__private_method()
def __init__(self):
self.__internal = Base.__Internal(self)
return
def __private_method(self):
print "hurray"
return
if __name__ == "__main__":
b = Base()
It results in:
hurray
You must use BaseClassName.methodname(self, arguments) or BaseClassName.field
Example (very ugly code):
class Base(object):
some_field = "OK"
class Internal(object):
def __init__(self, parent):
self.__parent = parent
def change_some_field(self):
Base.some_field = "NOP"
def __init__(self):
self.__private = "val"
self.__internal = Base.Internal(self)
def show_field(self):
print self.some_field
def change_some_field(self):
self.__internal.change_some_field()
def main():
a = Base()
a.show_field()
a.change_some_field()
a.show_field()
return 0
if __name__ == '__main__':
main()
You can find a very useful resources at Why are Python's 'private' methods not actually private?

Python: Class and Subclass issue

I have this code:
class main():
params = {}
class a(main):
def __init__(self):
self.params['test'] = "111aa"
print self.params
class b(main):
def __init__(self):
self.params['be'] = "222bbb"
print self.params
a()
#{'test': '111aa'}
b()
#{'test': '111aa', 'be': '222bbb'}
I need from b to print only {'be': '222bbb'}
Is there any way how to do it ?
Thanks
Try this:
class main(object): # use new-style classes!
def __init__(self):
self.params = {}
class a(main):
def __init__(self):
super(a, self).__init__()
self.params['test'] = "111aa"
print self.params
class b(main):
def __init__(self):
super(b, self).__init__()
self.params['be'] = "222bbb"
print self.params
Notice that in your code params was defined as a class attribute. By defining it in __init__ of the superclass, we're stating that it's an instance attribute. Also notice that the subclasses call __init__ on the superclass.
In this way, we're making sure that each instance has its own params attribute, without sharing it. You can't expect to share an object between instances and have each one with different values for it, it's a contradiction.

Categories

Resources