Getting variables from an outer class - python

I'm doing a project in Python which requires me to make a nested class. I need to get a variable from the class it is nested in but haven't been able to. I want to be able to get the self variables from Parent in the Child class but my code isn't working, is there any way I could inherit the Parent class' variables? Here is what I tried:
class Parent:
def __init__(self):
self.x = 1;
self.y = 2;
class Child:
def __init__(self):
pass;
def parent_vars(self):
att = super()["x"];
print(att);
parent = Parent();
child = parent.Child();
child.parent_vars();

In python, unlike in Java, a class serves more as a namespace than as an object. An inner class (in this case Parent.Child) is no different semantically than the same class defined as a standalone - the outer class is simply how it's accessed (and it's accessed statically, not requiring an instance - again unlike Java).
If you want a Child to take its Parent's variables, you'll need to tell the Child explicitly which object is its Parent:
class Parent:
def __init__(self):
self.x = 1
self.y = 2
class Child:
def __init__(self, parent):
self.parent = parent
def parent_vars(self):
att = self.parent.x
print(att)
par = Parent()
child = Parent.Child(par) # note how `Parent.Child`, not `par.Child()`
child.parent_vars()
# 1

Related

Python inheritance changing child class field

I am creating a database in a for of classes with inheritance. I would like Child class to inherit all field of parent class, however it doesn't happen as I am getting "AttributeError: 'Child' object has no attribute 'default'". If I define 'default' variable in Child class, I will get it working, but I want that Child inherited parent value for 'default' and not redefine it again at Child class. If I don't specify __init__ method in Child class, all fields are inherited, but I can't change their value.
#!/usr/bin/env python3
import sys
class Parent():
def __init__(self, y, x):
self.result = self.action(x,y)
default = 5
def action(self,x,y):
return (x*y)
def setResult(self, x):
def __init__(self, y, x):
self.result = x
class Child(Parent):
def __init__(self, y, x):
self.result = self.action(x,y)
def action(self,x,y):
return (x/y)
def main(argv):
data = Child(2,3)
print (data.result)
print (data.default)
if __name__ == "__main__":
main(sys.argv[1:])
To consolidate the comments you received into an actual answer:
class Parent():
def __init__(self, y, x):
self.result = self.action(x,y)
self.default = 5 #----- this requires a "self" to attach to any instance of the class
class Child(Parent):
def __init__(self, y, x):
super().__init__(y, x)
self.result = self.action(x,y)
To restate everything that has been stated in the comments:
You are overriding __init__ by making a function for it.
__int__ is a built-in function, if you don't make one yourself - python uses one it makes itself. __init__ is always run when a class is being initiated.
When you declare variables to self in this function, you are adding the variables to any instance of the class that is created. (as opposed to using self in some other function)
By writing your own version of __init__ you are taking on the burden of making sure that it creates every value the class is supposed to have - for cases where you want to make use of inheritance, this is why we have the super() function.
The super() function is used to give access to methods and properties of a parent or sibling class.
By calling super().__init__(y, x) you call Parent()'s __init__ function and thus 'inherit' its values / settings / properties.
Just to crystallize the subject more - the following two classes are (effectively) identical:
class Child(Parent):
def __init__(self, y, x):
super().__init__(y, x)
def action(self,x,y):
return (x/y)
class Child(Parent):
def action(self,x,y):
return (x/y)
Further reference:
https://www.w3schools.com/python/gloss_python_class_init.asp
https://www.w3schools.com/python/ref_func_super.asp

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

How to bring variables of super method into child method in Python3

I am implementing a subclass Child where an overwritten method some_method calls the parent method first. I want to use variable a from the parent method in the child method. Is there a neat way to do this without having to modify the code of Parent?
class Parent:
def __init__(self):
pass
def some_method(self):
a = 0
class Child(Parent):
def __init__(self):
super().__init__()
def some_method(self):
super().some_method()
b = a - 1 # Here I would like to keep using `a`

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