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()
Related
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!
is it possible to achieve type inheritance without overwriting class methods? Take for example this code:
class Parent:
def special_method(self, name):
print("hello, {}!".format(name))
class Child:
def __init__(self, injected_parent):
self.parent = injected_parent
def special_method(self):
self.parent.special_method("Homer Simpson")
parent = Parent()
child = Child(parent)
child.special_method()
# hello, Homer Simpson!
Works as expected, but I want the type of child to be Parent and not Child:
print(type(child))
<class '__main__.Child'>
One way I've seen it done is to extend Child with:
class Child:
def __init__(self, injected_parent):
self.parent = injected_parent
self.__class__ = Parent
...
However, then child's special_method gets overwritten:
parent = Parent()
child = Child(parent)
child.special_method()
# TypeError: special_method() missing 1 required positional argument: 'name'
Any way to make child have type Parent without side-effects?
It seems like what you want to do is just regular inheritance, but as #juanpa.arrivillaga pointed out, you are using composition instead. What you are trying to do by changing the __class__ and overloading a method will not work. Here is an example using inheritance which will allow you to overload the method while still having access to the original method and to have child be an instance of parent which seems to meet your requirements:
class Parent:
def special_method(self, name):
print("hello, {}!".format(name))
class Child(Parent):
def special_method(self):
super().special_method("Homer Simpson")
child = Child()
Now, child will still have a type of Child, but with classes what you want to be checking instead is whether it is an instance of the superclass using isinstance:
>>> child.special_method()
hello, Homer Simpson!
>>> type(child)
<class '__main__.Child'>
>>> isinstance(child, Parent)
True
Here is my code:
Here is my error:
I'm very confused why this is happening. I'm using an instance of the class JinderBot and the __init__ function clearly sets the driver attribute. Please help point out my mistake.
I'm using PyCharm and Python 3.7.
You need to add methods to the class to access and set the attributes.
class JinderBot:
def __init__(self):
self.atrib = “foobar”
def _get(self):
return self.atrib
def _set(self, atrib)
self.atrib = atrib
bot = JinderBot()
print(bot._get())
bot._set(“updating attribute”)
print(bot._get())
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
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).