Python inheriting instance variable when value of the variable changes dynamically - python

I have to inherit dynamic value of the Parent instance variable a.I've tried using super which gets the value which is defined in the init constructor of the Parent and also have tried passing Parent object.
Please refer the code snippet below
class Parent(object):
def __init__(self):
self.a = 1
def test(self):
self.a = 2
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
class Child1(Parent):
def __init__(self, parent):
self.a = parent.a
p = Parent()
c = Child()
c1 = Child1(p)
p.test()
print p.a #2
print c.a #1
print c1.a #1
If I use below code, the problem gets solved.However is there any way to get the instance variable value of parent which is altered after initialization.
c.test()
print c.a #2
c1.test()
print c1.a #2
Please suggest any solution for this problem.

You need to use delegation here. Instead of directly assigning self.a to the value of parent.a, you should store the parent, and then define a property that gets the value of the parent's a on request.
class Child1(object):
def __init__(self, parent):
self.parent = parent
#property
def a(self):
return self.parent.a

Related

Expensive operation in parent class performed once for all child classes

I have two classes that inherit from the same base class. In the base class I have a very expensive method that must be ran only once and whose generated attributes must be available to the child class. How do I achieve that?
In the example below, the instantiation of the B and C child classes will both run expensive_op in A. I'd like expensive_op to be called only when I call b=B(). A is never called directly.
Moreover, I want to be able to modify the attributes of the parent class from the child class as done, for example, in the modify method in B.
Anyone able to help?
class A:
def __init__(self):
self.expensive_op()
def expensive_op(self):
self.something = #something ugly and expensive
class B(A):
def __init__(self):
super().__init__()
def modify(self,mod):
self.something = self.something+mod
class C(A):
def __init__(self):
super().__init__()
b = B()
c = C()
EDIT: in response to #0x5453's comment, do you mean the modification of A below?
class A:
def __init__(self):
self.something = None
def expensive_op(self):
if self.something is not None:
self.something = #something ugly and expensive
But if I call b=B() and then c=C(), the latter won't know about self.something. The output is
b=B()
c=C()
b.expensive_op(3)
print(b.something)
>>> 3
print(c.something is None)
>>> True
Am I missing something?

Can python's 'super' give child classes its parent classes class variables

I am trying to make it to where I can have multiple child classes from, for example class a, and I want all of the variables declared in class a's __init__ method to be in all of the child classes, while also not needing to enter any *args into the __init__ method.
My example parent class is:
class a:
def __init__(self):
self.t = 5
and my example child class is:
class c(a):
def __init__(self):
super().__init__()
does class c have the variable t from class a?
Would it be equal to 5?
While messing around with this, I get the error AttributeError: type object 'c' has no attribute 't', but shouldn't super().__init__() get the variable t from class a and make it to where class c has it too?
Yes, you're right, but the error occurs because you trying to access t on the class itself and not its instance. The following should work:
inst = c()
print(inst.t) # 5
class A:
def __init__(self):
self.a = 1
class B(A):
def __init__(self):
super().__init__()
self.b = self.a
print(self.b)
if __name__ == '__main__':
B()
Code example like this. You'll get 1 in command line. So just use self.attr.

How Child class constructor set the parent class attribute

In python, how can I setup the Parent class attributes in Child Class constructor.
My Parent class has 2 attributes which set in its constructor:
class Parent:
def __init__(self):
self.attribute1 = "abc"
self.attribute2 = 1
def afunction():
# something to print attributes"
print(self.attribute1 + self.attribute2)
In my child class, in the construtor, I try to override the attribute1, attribute2 by
class Child(Parent):
def __init__(self):
super.attribute1 = "def"
super.attribute2 = 3
But I get error TypeError: can't set attributes of built-in/extension type 'super'
What i want to when x = Child() x.afunction(), I should see it print "def3"
You should use the inheritance right way. Your parent class already have 2 attributes, but you are not exposing them to be parametrized to be instantiated by clients as well as subclasses. You could do this as follows:
class Parent:
def __init__(self, attribute1="abc", attribute2=1):
self.attribute1 = attribute1
self.attribute2 = attribute2
def afunction(self):
print(self.attribute1 + str(self.attribute2))
class Child(Parent):
def __init__(self, attribute1="def", attribute2=3):
super().__init__(attribute1, attribute2)
Child().afunction()
Child("test", 3).afunction()
This way you are allowing clients to provide value for your attributes, not reassign them in child. Also exposing attributes to the clients so they can pass them if they need else it uses the default value
To build up on my comment:
class Parent:
def __init__(self):
self.attribute1 = "abc"
self.attribute2 = 1
class Child(Parent):
def __init__(self):
self.attribute1 = "def"
self.attribute2 = 3
c = Child()
In this case, the child is initialize. In the initialization 2 attributes are created with the value def and 3. The attributes are never initialized with the values from the parent class.
Alternatively:
class Parent:
def __init__(self):
self.attribute1 = "abc"
self.attribute2 = 1
class Child(Parent):
def __init__(self):
super().__init__()
self.attribute1 = "def"
self.attribute2 = 3
c = Child()
This time, the attributes are first initialized during the super() call by calling the function __init__() from the parent class. And then they are overridden.
Which one you prefer depends on your application, but either way, you can create the attribute directly in the child class as they don't belong to one specifically.
Got It In Place Of Super() try Acccesing It With Parent.
And Then Print It I Definitely Say You Will Get Your Answer :'def'

How to pass all class variables from a parent *instance* to a child class?

Here's an example of what I'm trying to do:
class Parent():
def __init__():
self.parent_var = 'ABCD'
x = Child(self) # self would be passing this parent instance
class Child():
def __init__(<some code to pass parent>):
print(self.parent_var)
foo = Parent()
Now I know what you're thinking, why not just pass parent_var itself to the child instance? Well my actual implementation has over 20 class variables in Parent. I don't want to have to manually pass each variable to the __init__ of the Child instance that's instantiated in Parent-- is there a way to make all Parent class variables available to Child?
EDIT - SOLVED:
This is the way I found that works:
class Parent():
def __init__(self):
self.parent_var = 'ABCD' # but there are 20+ class vars in this class, not just one
x = Child(self) # pass this parent instance to child
class Child():
def __init__(self, parent):
for key, val in vars(parent).items():
setattr(self, key, val)
print(self.parent_var) # successfully prints ABCD
foo = Parent()
If you inherit from the parent class all variables will be present in child classes. Use super init in the child to make sure the parent class instantiates.
class Parent:
def __init__(self):
self.parent_var = 'ABCD'
class Child(Parent):
def __init__(self):
super().__init__()
child = Child()
print(child.parent_var)
prints:
'ABCD'
You would pass the instance of Parent like you would any value.
class Parent:
def __init__(self):
self.parent_var = 'ABCD'
x = Child(self)
class Child:
def __init__(self, obj):
print(obj.parent_var)
Found a solution and wanted to post the answer in case anyone who finds this needs it:
class Parent():
def __init__(self):
self.parent_var = "ABCD" # just an example
x = Child(self) # pass this parent instance (this object) to child
class Child():
def __init__(self, parent):
# copies variables from passed-in object to this object
for key, val in vars(parent).items():
setattr(self, key, val)
print(self.parent_var) # successfully prints ABCD
foo = Parent()

Access parent class instance attribute from child class instance?

How to access "myvar" from "child" in this code example:
class Parent():
def __init__(self):
self.myvar = 1
class Child(Parent):
def __init__(self):
Parent.__init__(self)
# this won't work
Parent.myvar
child = Child()
Parent is a class - blue print not an instance of it,
in OOPS to access attributes of an object it requires instance of the same,
Here self/child is instance while Parent/Child are classes...
see the answer below, may clarify your doubts.
class Parent():
def __init__(self):
self.myvar = 1
class Child(Parent):
def __init__(self):
Parent.__init__(self)
# here you can access myvar like below.
print self.myvar
child = Child()
print child.myvar
Parent does not have an attribute called myvar. Only instances of parent have that attribute. From within a method of Child, you can access that attribute with self.myvar.
Alternative to using inheritance
The current answers are coming from an inheritance perspective, but this isn't always what you want -- sometimes you might want the child to be an entirely different type of object to the parent, but that still has access to the parent attributes.
For a business analogue, think of Excel Workbooks which have Worksheet children, which themselves have Range children, and so on.
Only Child
An alternative approach (and not the only one) is to pass the parent as an argument to the child to create a property that corresponds to the parent:
class Parent(object):
def __init__(self, parent_value):
self.parent_value = parent_value
self.child = Child(self)
class Child(object):
def __init__(self, _parent):
self.parent = _parent
self.child_value = 0
new_parent = Parent(1)
print(new_parent.parent_value) # prints 1
new_child = new_parent.child
print(new_child.child_value) # prints 0
print(new_child.parent.parent_value) # prints 1
new_parent.parent_value = 100
print(new_child.parent.parent_value) # prints 100
Note that this instantiates the child at the same that that new_parent is instantiated. To access the parent's attributes, just go through the parent property.
Multiple Children
You could extend this so that you can create multiple instances of the Child class through the new_parent object. The code below is one simple way of doing this which replaces the child property with a children property and an add_child method.
class Parent(object):
def __init__(self, parent_value):
self.parent_value = parent_value
self.children = []
def add_child(self, child_value):
new_child = Child(child_value, _parent=self)
self.children.append(new_child)
return new_child # allows add_child to assign a variable
class Child(object):
def __init__(self, child_value, _parent):
self.parent = _parent
self.child_value = child_value
new_parent = Parent(1)
# add 3 Child instances with child_values 2, 4, 8
[new_parent.add_child(v) for v in [2, 4, 8]]
# add another child that utilises the return statement
extra_child = new_parent.add_child(16)
for child in new_parent.children:
print(child.child_value) # prints 2, 4, 8, 16
print(child.parent.parent_value) # prints 1
new_parent.parent_value = 32
for child in new_parent.children:
print(child.parent.parent_value) # prints 32
# prove that extra_child is new_parent.children[3]
extra_child.child_value = 64
print(new_parent.children[3].child_value) # prints 64
You need to initiate the parent class first via so-called proxy object using command "super".
So the code will be like this:
class Parent():
def __init__(self):
self.myvar = 1
class Child(Parent):
def __init__(self):
super.__init__()
child = Child()
print child.myvar

Categories

Resources