I am new to python and asking very basic question. I am trying to understand multiple inheritance. I have two parent classes i.e Speciy and Living and one child class Bird but when i run the following program, i get error 'Bird' object has no attribute '_Living__house'.Please tell me what i am doing wrong
But when i use single inheritance i.e class Bird(Speciy) or class Bird(Living)it works fine. So only the error comes when i use multiple inheritence
class Speciy:
def __init__(self,legs=4,colour="White"):
self.__legs=legs
self.__colour=colour
def get_legs(self):
return self.__legs
def set_legs(self,legs):
self.__legs=legs
def get_colour(self):
return self.__colour
def set_colour(self,colour):
self.__colour=colour
class Living:
def __init__(self,house="city"):
self.__house=house
def get_house(self):
return self.__house
def set_house(self,house):
self.__house=house
class Bird(Speciy,Living):
def __init__(self,wings=2):
super().__init__()
super().__init__()
self.__wings=wings
def get_wings(self):
return self.__wings
def set_wings(self,wings):
self.__wings=wings
b1=Bird(4)
print(b1.get_wings())
b1.set_colour("Green")
print(b1.get_colour())
print(b1.get_house())
I have solved the issue my self using
Speciy.__init__(self,legs,colour)
Living.__init__(self,house)
Related
I have the following situation:
class AbstractSpeaker(ABC):
#abstractmethod
def say_hello(self)->None:
pass
"""... other abstract and maybe even concrete methods ..."""
class BasicGreeter:
"""implements a basic say_hello method so that Speakers
don't need to implement it"""
def __new__(cls):
r=object.__new__(cls)
r._language=Language.English #assume that Language is an appropriate Enum
return r
#property
def language(self)->Language:
return self._language
#language.setter
def language(self, newLanguage:Language):
self._language=newLanguage
def say_hello(self)->None:
if self.language is Language.English:
print("Hello")
elif self.language is Language.German:
print("Hallo")
elif self.language is Language.Italian:
print("Ciao")
else:
print("Hi")
class Person(BasicGreeter, AbstractSpeaker):
def __init__(self, name):
self.name=name
"""goes on to implement everything AbstractSpeaker speaker commands but should
use the say_hello method from BasicGreeter, who should also hold the language
information.
"""
But when I want to generate a new Person I get an TypeError:
>>> peter=Person('Peter')
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
peter=Person('Peter')
TypeError: __new__() takes 1 positional argument but 2 were given
Now I get that it has something to do with the fact that I have implemented a new method in BasicGreeter because when I rewrite BasicGreeter to use an init method instead of the new-method and then explicitly call super.init() in the Person's init it works. But I wanted to know if there is any way to do this with the new method as having to invoke super.init() in every Speakers init can be a bug source if ever forgotten. Any ideas, can this (a class implementing basic compliance in some areas for an abstract class so that children of that abstract class don't need to implement the same code) be done? I know that I could always go the 3 generation route making the BasicGreeter an abstract class, but I think that is more elegant way as it allows BasicGreeter to be used for other families f.e. I might have a class Robot with a subclass FriendlyRobot that could also make use of inheriting from BasicGreeter but a Robot is not necessarily a speaker and vice versa.
The error gives you the solution, simply let the new method to take the arguments even if you don't use them:
from abc import ABC, abstractmethod
class Language():
English = 'english'
class AbstractSpeaker(ABC):
#abstractmethod
def say_hello(self)->None:
pass
"""... other abstract and maybe even concrete methods ..."""
class BasicGreeter:
"""implements a basic say_hello method so that Speakers don't need to implement it"""
def __new__(cls, *args, **kwargs): # Fix to your code
# print(args,kwargs)
r=object.__new__(cls)
r._language=Language.English
return r
#property
def language(self)->Language:
return self._language
#language.setter
def language(self, newLanguage:Language):
self._language=newLanguage
def say_hello(self)->None:
if self.language is Language.English:
print("Hello")
elif self.language is Language.German:
print("Hallo")
elif self.language is Language.Italian:
print("Ciao")
else:
print("Hi")
class Person(BasicGreeter, AbstractSpeaker):
def __init__(self, name):
self.name=name
"""goes on to implement everything AbstractSpeaker speaker commands but should
use the say_hello method from BasicGreeter, who should also hold the language
information.
"""
This piece of code works, said that, I'm not sure in what you need such a structure inside new, is a way of making a singleton?
Hello im trying to make a chess game, however i cant seem to get this class to work, how to do i get the variable pawn_black1_status in the main block to change after i alter it in the class? If it works correctly it should print "dead"
class Status(object):
def __init__(self,piece,pawn_black1_status):
self.piece=piece
self.pawn_black1_status=pawn_black1_status
def Status2(self,piece,pawn_black1_status):
self.piece=piece
self.pawn_black1_status=pawn_black1_status
self.pawn_black1_status="dead"
pawn_black1_status="alive"
Pawn1b_status=Status("p1b",pawn_black1_status)
Pawn1b_status.Status2("p1b",pawn_black1_status)
print(pawn_black1_status)
You must reference the class you have created to access the variable within it.
class Status(object):
def __init__(self,piece,pawn_black1_status):
self.piece=piece
self.pawn_black1_status=pawn_black1_status
def Status2(self,piece,pawn_black1_status):
self.piece=piece
self.pawn_black1_status=pawn_black1_status
self.pawn_black1_status="dead"
pawn_black1_status="alive"
Pawn1b_status=Status("p1b",pawn_black1_status)
Pawn1b_status.Status2("p1b",pawn_black1_status)
print(Pawn1b_status.pawn_black1_status)
I'm using Python 3.7.6 with PyCharm. I want my code to work as a nice internal API with code completion appearing for objects so I want to use typing.
I'm trying to find a good pattern for when:
There are two groups of classes with each group having it's own inheritance tree
and objects from one group are composed of lists of objects from other group
(example below)
I've found a way below but it feels like a hack. What's the right (or better) way to do this?
from typing import List, Type
class Leg:
def step(self):
print("step")
class DuckLeg(Leg):
def paddle(self):
print("splosh")
class Biped:
def __init__(self, leg_type: Type[Leg]):
self.legs: List[leg_type] = [leg_type(), leg_type()]
def walk(self):
for leg in self.legs:
leg.step()
class Duck(Biped):
def __init__(self):
super().__init__(leg_type=DuckLeg)
self.legs: List[DuckLeg] = self.legs # A hack?
my_duck = Duck()
my_duck.walk() # code-completion appears for .walk()
my_duck.legs[0].paddle() # code-completion appears for .paddle()
Edit 1: This question is not about where to put the type annotations but how to ensure code-completion works in this context. If the following line is commented-out...
self.legs: List[DuckLeg] = self.legs
...the code will still run because of duck-typing but code-completion will not appear for .paddle() and when manually entered PyCharm code inspection will report: Unresolved attribute reference 'paddle' for class 'Leg'.
Not sure if this actually solves your problem but I think it's cleaner than what you propose:
from typing import List, Type
class Leg:
def step(self):
print("step")
class DuckLeg(Leg):
def paddle(self):
print("splosh")
class Biped:
LegType = Leg
def __init__(self):
# self.LegType always gives the correct leg type for the instance
self.legs: List[self.LegType] = [self.LegType(), self.LegType()]
def walk(self):
for leg in self.legs:
leg.step()
class Duck(Biped):
LegType = DuckLeg
def __init__(self):
super().__init__()
Example
function.py
class testClass(object):
def functionA(self):
#doSomething
self.Qlabel.clear()
main.py
class mainClass(object):
def __init__(self, parent = #something):
#initialize something
super(mainClass, self).__init__(parent)
self.setupUi(self)
self.Qlabel.clicked.connect(self.testFunc)
def testFunc(self):
import function as FT
FT.testClass().functionA(self)
I tried connecting my PyQt function.py to main.py. It keeps giving me this TypeError: functionA() takes exactly 1 argument (2 given).
If I take away the 'self' in so that it's FT.testClass().functionA(), then I get AttributeError: 'testClass' object has no attribute 'Qlabel'
I saw in PyQt : accessing elements from outside the class that it works with just using obj but not with classes.
I would like to understand how to fix this and also why my previous method doesn't work. Any help would be appreciated!
I have managed to get it working. The problem was basically in function.py, I was using self.Qlabel.clear() instead of object.Qlabel.clear(),
This is the working code.
function.py
class testClass(object):
def functionA(self, object):
#doSomething
object.Qlabel.clear()
main.py
class mainClass(object):
def __init__(self, parent = something):
#initialize something
super(mainClass, self).__init__(parent)
self.setupUi(self)
self.Qlabel.clicked.connect(self.testFunc)
def testFunc(self):
import function as FT
FT.testClass().functionA(self)
In the definition of functionA make one more Entry.
For e.g.
def functionA(self, mainClassObj):
#doSomething
self.Qlabel.clear()
Cause of the error is you're calling testclass function with one extra argument.Whereas you define it with one argument.
Note: You have to initiate Qlabel :
def functionA(self, mainClassObj):
#doSomething
from PyQt5.QtWidgets import QLabel
Qlabel().clear()
This should work for you.
Here is my program structure:
class parent(object):
def __init__(self): pass
def __post_init_stuff(self):
#post initialization stuff
class child(parent):
def __init__(self):
#dostuff
self.__post_init_stuff()
def otherfunc(classname, args):
classname(args)
otherfunc(child)
The problem that I'm having is that when otherstuff(child) executes, I get this error:
AttributeError: 'child' object has no attribute '_child__post_init_stuff'
Any advice?
Names that start with __ in Python are like protected in C++. You could name with only one underscore instead or access it as self._parent__post_init_func, since this is its mangled name within the scope. I recommend the first thing, since this is ugly and hacky.