Python - access parent's class attribute from child's class method - python-3.x

i'm stuck at this poin in my code where i need a method of a child class to use an attribute of the parent's class.
Here are the classes:
class Parent:
def __init__(self, section):
self.section = section
class Child(Parent):
def __init__(self, section):
super().__init__(section)
self.name = self.get_name()
def get_name(self):
section = self.section
name = "somestring_" + section
return name
Now when executing the code below i get that Child does not have the section attribute:
child = Child('section')
print(child.name)
The expected output of the code should be: somestring_section.
I've tried calling the attribute directly with: section = super().section and doesn't work.
Also tried to call it like this: section = Parent.section and doesn't work.
Also tried to call it like this: section = super(Child).section and doesn't work.
Examples taken from this post here on stackoverflow: Accessing attribute from parent class inside child class
Where i've made the error?
Thanks in advance

Related

Class Inheritance python require fill child class name

it might be a silly question since I'm new to Python.
However, I hope someone can explain this because I try to find lots of resource but still hardly understand the mechanism behind.
So I create a Parent Class and a Child Class. Parent Class have set_name, get_name method
In Child Class, I defined a new method call Turn_Uppercase which calling get_name then uppercase the name. And when using Turn_Uppercase Method, I have to filled in Child Class Name, otherwise it would not work.
Can someone explain the mechanism here!
Let's me explain in code:
So first I create a Parent Class with get_name and set_name method.
class Parent:
def __init__(self, text_input):
self.__name = ""
self.name = text_input
#property #this is get_name
def name(self):
return self.__name
#name.setter #this is set_name
def name(self, text_input: str):
if isinstance(text_input, str): # check input has to be string
self.__name = text_input
else:
print('Wrong type of data')
Then I create a Child Class with new method called Turn_uppercase
class Child_to_parent(Parent):
def __init__(self):
pass
def turn_uppercase(self):
return self.name.upper()
Now I put in some object and use Turn_uppercase Method, I have to fill in Child Class Name
test1 = Child_to_parent
test1.name = "abcdef" # using parent method
print(f'{test1.turn_uppercase(Child_to_parent)}') # using child method
When using parent method through property name, I don't need to declare Child Class Name, but when it comes to use Turn_uppercase Method then I have to.
Why it works this way?
This line makes all the difference
test1 = Child_to_parent
You are not creating an object here, instead merely assigning a reference to the class itself. What you must be doing is
test1 = Child_to_parent() #>Create the object!
test1.name = "abcdef"
print(f'{test1.turn_uppercase()}')
Now why it works with the class? It's because you attached a attribute to the class called name. The method you called used the class as argument and evaluated the class attribute!
Read this answer for a better understanding!

How do I override a method from within an inherited method in Python

I'm rather new to class inheritance and need some assistance
I have a problem, where I want to override a parent class method, after it has been called from another inherited parent class method.
The basic concept looks something like this:
class Parent:
"""Parent class, that defines the logical workflow"""
def __init__(self):
pass
def outer_method(self):
# This method is called from the sub_classes
# everything in here is the same for all sub_classes
self.__inner_method(self)
def __inner_method(self):
# This method is called from self.outer_method()
# Everything in here will be handled differently by each sub_class
# And will therefore be overridden
pass
class Child(Parent):
"""Sub_class, that inherits from the Parent class"""
def __init__(self):
super().__init__()
def __inner_method(self):
# this should override Parent.__inner_method()
super().__inner_method()
print('Do some custom operations unique to this Sub_class')
The idea here is, that the Child class calls outer_method which then calls __inner_method, which I want to be overridden by the child class.
But that doesn't work.
When I run this script,
def main():
MyChild = Child()
MyChild.outer_method()
if __name__ == "__main__":
main()
what happens is that instead of calling Child.__inner_method(), Parent.__inner_method() is called.
How can I get the Child class to override the inner method of the parent class, after it has been called from the inherited outer method?
The reason of the problem is the name you choose, python apply an special treatment to a class members if its name start with __ but doesn't end with that, called name mangling, the reason it does that is in order to get python version of private variables/methods, so your __inner_method got renamed to _Parent__inner_method as result and any call to __inner_method withing the parent class gets modify to be a call to this renamed method, and because the same happens to the child class its end with a _Child__inner_method of it own which of course messed up with the inheritance mechanism if this isn't desired.
The solution is simple, rename all __inner_method to _inner_method.
A single _ is the convention for private stuff when you don't want the name mangling, with __ is for when you want it to be extra private if you will...

Python Inheritance: Why does the Folder class inherit from the File class

The below code is from a book I'm reading related to OOP in Python 3. Can someone help me understand the logic of the below? It seems counterintuitive that the Folder class inherits from the File class. For example, in the below, when a Folder is instantiated, it seems that a File is also instantiated with the same name but in reality you would not want this to happen. What am I missing?
class File:
def __init__(self, name):
self.name = name
class Folder(File):
def __init__(self, name):
super().__init__(name)
self.children = []
root = Folder("")
etc = Folder("etc")
root.children.append(etc)
etc.children.append(File("passwd"))
etc.children.append(File("groups"))
httpd = Folder("httpd")
etc.children.append(httpd)
httpd.children.append(File("http.conf"))
var = Folder("var")
root.children.append(var)
log = Folder("log")
var.children.append(log)
log.children.append(File("messages"))
log.children.append(File("kernel"))

How to use parent class to enforce subclasses to set value to an attribute?

I want the Parent class to have a checking mechanism to ensure all its subclasses to set an actual value to the attribute name. I found something here.
class Parent(object):
#name = None
def __init__(self):
if self.name == None:
raise NotImplementedError('Subclasses must define name')
class Child1(Parent):
pass
class Child2(Parent):
name = 'test'
class Child3(Parent):
def __init__(self):
self.name = 'test'
class Child4(Parent):
def __init__(self):
pass
#obj1 = Child1() # Expected output: NotImplementedError: Subclasses must define bar
obj2 = Child2()
obj3 = Child3()
obj4 = Child4() # I want the NotImplementedError is raised here as well, but it doesn't
The problem is as long as there is an __init__ method in the subclass, it overwrites the Parent class and the raise NotImplementedError is no longer in effect.
My current working solution is:
class Child5(Parent):
def __init__(self):
self.name = 'test'
super().__init__()
obj5 = Child5()
which seems to work, but I wonder if it's a proper implementation, or if it may have some hidden pitfalls, and also if I should learn to use/implement #abstractproperty instead of this solution?
Here, you need to understand when you parent class constructor gets called. Note that while creating child class objects, if child class has a constructor it is called by default. It is up to us whether we want to call parent class constructor as well and this shall be done by us. However if child class doesn't have a constructor, then the base class constructor is called.
So with your Child1(), parent constructor is called by default so it raises the exception.
In your Child2() as well parent constructor is called. However do note here that name variable is static and can even be accessed as Child2.name. And thus no exception is raised.
Your Child3 class has a constructor has a constructor thus parent constructor is never called and thus check for presence of name is actually never made. So you do need to add following line to to child constructor.
super().__init__()
This call shall be made after declaring name if constructor defines name. And this is what you have done in your Child5 class.
For exactly the same reason as above, exception was not captured in Child4. Following will check this condition in Child4:
class Child4(Parent):
def __init__(self):
super().__init__()
You can check when constructor is being called, by simply adding a unique print statement(such as print(1), print(2), and so on) in each constructor (preferably at the beginning).

Unable to inherit from QAbstractItemModel

I'm new to model/view in PyQt and I'm having trouble creating an object that inherits from the QAbstractItemModel class. Here's the class that inherits from it:
class MyCustomDataModel(QAbstractItemModel):
def __init(self, parent = None):
super(MyCustomDataModel, self).__init__(parent)
self.parent = parent
Here's another class that tries to instantiate an object of the above type:
class MyCustomType(AnotherCustomTypeThatInheritsQListWidgetItem):
def __init__(self, parent = None):
super(MyCustomType, self).__init__(parent)
# Instantiate a model:
self.dataModel = MyCustomDataModel(self)
The above instantiation is throwing the following error at runtime:
"QAbstractItemModel(QObject parent = None): argument 1 has unexpected type 'MyCustomType'" I cannot see what the problem is here, but I'm pretty new to Python / PyQt. Can someone please point out what I've done wrong? I've tried calling the instantiation line and not passing anything in but I get the same error.
This might be more appropriate as a comment instead of an answer.
Try updating the line where you pass the MyCustomType instance to MyCustomDataModel:
self.dataModel = MyCustomDataModel(self)
Instead use:
self.dataModel = MyCustomDataModel()

Resources