class Shape:
def __init__(self,center,name):
self.__name = name
self.center = center
def getName(self):
return self.__name
def __add__(self,otherShape):
return Shape(name = self.__name, center = self.center + otherShape.center)
class Size:
def __init__(self,surface,magnitude):
self.surface = surface
self.magnitude = magnitude
def __eq__(self, otherSize):
try:
a = self.magnitude == otherSize.magnitude and self.surface == otherSize.surface
except:
print('Wrong type of atributes')
return a
class Dreieck(Size,Shape):
def __init__(self,center,name,surface,magnitude,a,b,c):
Shape.__init__(self,center,name)
Size.__init__(self,surface,magnitude)
Dreieck.a = a
Dreieck.b = b
Dreieck.c = c
def pitagoras(self):
if self.a+self.b==self.c and self.a**2 + self.b**2 == self.c**2:
return True
else:
return False
def __add__(self,otherDreieck):
return Dreieck(self.center, self.__name, self.surface, self.magnitude,self.a+otherDreieck.a, self.b+otherDreieck.b, self.c+otherDreieck.b)
I am doing a simple example of multiple inheritance in Python, and I can't find why by adding two objects of class Dreieck I get an AttributeError 'Dreieck' object has no attribute 'name'. I suppose it is because the name attribute is private, but I thought I was inheriting it here:
Shape.__init__(self,center,name)
Outside the class itself, private names are mangled. See Private Variables and Class-local References.
You can work around it by using the mangled name in your code. In other words try referencing it as self._Shape__name.
Related
I am trying to create a setter for my private self.__food variable. Basically i want the childclass Tiger to change the private variable which has a condition to limit the value over 100. However i receive an error : TypeError: 'int' object is not callable
Where am I wrong and how can i fix this? Thanks
class Animal:
def __init__(self,foodamount=10, location = 'Australia'):
self.__food = foodamount
self.location = location
#property
def foodamt(self):
return self.__food
#foodamt.setter
def foodsetter(self, foodamount):
if self.__food >100:
self.__food = 100
else: self.__food = foodamount
class Tiger(Animal):
def __init__(self,colour = 'orange'):
super().__init__(location ='programming and gaming')
self.colour = colour
an = Tiger()
an.colour='red'
print(an.colour)
ansetfood = an.foodsetter(1000)
print(ansetfood)
I see a couple problems.
When using a property, you do not manually call the setter's name like an.foodsetter(1000). You use attribute assignment syntax, like an.foodamt = 1000. This is the entire point of properties: to have transparent attribute-like syntax while still having function-like behavior.
You should be comparing foodamount to 100, not self.__food.
a property's getter and setter should have the same name.
class Animal:
def __init__(self,foodamount=10, location = 'Australia'):
self.__food = foodamount
self.location = location
#property
def foodamt(self):
return self.__food
#foodamt.setter
def foodamt(self, foodamount):
if foodamount >100:
self.__food = 100
else: self.__food = foodamount
class Tiger(Animal):
def __init__(self,colour = 'orange'):
super().__init__(location ='programming and gaming')
self.colour = colour
an = Animal()
an.colour='red'
print(an.colour)
an.foodamt = 1000
print(an.foodamt)
Result:
red
100
Just a simple class definition withh subclasses to show inheritance
import datetime
class LibaryItem: #The base class definition
def __init__(self, t, a, i): # initialiser method
self.__Title = t
self.__Author_Artist = a
self.__ItemID = i
self.__OnLoan = False
self.DueDate = datetime.date.today()
def GetTitle(self):
return(self.__Title)
# All other Get methods go here
def Borrowing(self):
self.__OnLoan = True
self.__DueDate = self.__DueDate + datetime.timedelta(weeks = 3)
def Returning(self):
self.OnLoan = False
def PrintDetails(self):
print(self.__Title, '; ', self.__Author_Artist,'; ',end='') # end='' Appends a space instead of a newline
print(self.__ItemID, '; ', self.__OnLoan,'; ', self.__DueDate)
class Book(LibaryItem):# A subclass definition
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
# This statement calls the constructor for the base class
self.__IsRequested = False
self.__RequestBy = 0
def GetIsRequested(self):
return(self.__IsRequested)
class CD(LibaryItem):
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
self.__Genre = ""
def GetGenre(self):
return(self.__Genre)
def SetGenre(self, g):
self.__Genre = g
Instantiating a subclass
ThisBook = Book('Title', 'Author', 'ItemID')
ThisCD = CD('Title', 'Author', 'ItemID')
This is my problem here I don't understand why the ThisBook the object's attribute doesn't change from False its default value to True.
# Using A method
print(ThisBook.GetIsRequested())
ThisBook.IsRequested = True
print(ThisBook.GetIsRequested())
Thank you a reason to why this doesn't work would be helpful
You probably meant to do
ThisBook.__IsRequested = True
which you can't do because of name mangling. You could write another setter.
But before you dive too deeply into writing a lot of getters and setters you should be aware that the pythonic way is to not use them. Or, if additional logic is required, to use the #property decorator.
class LibaryItem:
def __init__(self, title, author, itemid): # initialiser method
self.title = title
self.author = author
self.itemid = itemid
self._onloan = False
self.duedate = datetime.date.today()
#property
def onloan(self):
return self._onloan
#onloan.setter
def onloan(self, value):
if value:
self.duedate += datetime.timedelta(weeks = 3)
self._onloan = value
def __str__(self):
return "%s; %s; %s; %s; %s" % (self.title, self.author, self.itemid, self.onloan, self.duedate)
class Book(LibaryItem):
def __init__(self, title, author, itemid):
LibaryItem.__init__(self, title, author, itemid)
self.requested = False
self.requestby = 0
and then
ThisBook = Book('Title', 'Author', 'ItemID')
print(ThisBook.requested)
ThisBook.requested = True
ThisBook.onloan = True
print(ThisBook.duedate)
You can't access a field with 2 underscores prefix like that (see What is the meaning of a single- and a double-underscore before an object name?).
You need to write a proper setter:
def SetIsRequested(self, val):
self.__IsRequested = val
What you are experiencing is the typical silliness of dynamic languages. A field on class can be set w/o being declared and the interpreter can't help you by pointing out that you've just created a new field called "IsRequested" in your class. Saves you some typing but costs you in ability of your interpreter and IDE to prevent you from messing up.
I have three classes: Item, Weapon, and BrassSword
When I try to access one of BrassSword's attributes ex.(name,image,etc.) It says, AttributeError: class BrassSword has no attribute 'image'
Here's the code:
import pygame, math, random
class Item(object):
def __init__(self,name,image,reuseable,value):
self.image=pygame.image.load(image)
self.itemattrs = ['name','image','reuseable','value']
self.path = image
self.name = name
self.x=0
self.y=0
self.reusable = reuseable
self.value = value
self.rect = [self.x,self.y,self.image.get_size()[0],self.image.get_size()[1]]
def onUse(self):
pass
def onThrow(self):
pass
class Weapon(Item):
def __init__(self,name,image,value,damage,maxdamage,speed):
super(Weapon,self).__init__('Weapon',image,True,value)
self.itemattrs = ['name','image','damage','maxdamage','value','speed']
self.damage=damage
self.maxdamage=maxdamage
self.speed = speed # Cooldown in frames
self.cooldown = 0
def onUpdate(self):
self.cooldown -= 1
def onUse(self,targetEntity):
if self.cooldown > 0:
return
self.cooldown = speed
targetEntity.hp-=random.range(damage,maxdamage)
if targetEntity.hp <= 0:
targetEntity.onDie()
def onThrow(self):
pass # TODO: Add throwing weapons
class BrassSword(Weapon):
def __init__(self):
super(BrassSword,self).__init__('item.weapon.brass_sword','testlevel/Ball.png',True,value,3,10,12)
You didn't post the code that's actually causing the error - namely where you access the attribute. However, you can't access an instance attribute by referring to the class - they are stored in a separate __dict__. Your superclass sets these attributes when it is instantiated in __init__(), as a property of self. After this, they can only be accessed through that self instance.
If you are trying to access the attribute similarly to this:
a = BrassSword.image
instead, you want to access it something like this:
sword = BrassSword()
a = sword.image
or:
sword = BrassSword().image
If you want to have a single image shared across all BrassSword instances, you need to declare it a class attribute like this:
class BrassSword(Weapon):
image = 'path/to/image'
def __init__(...):
...
I have a program where an object creates another object. However, the second object that gets created needs to be able to access the first. Is this possible?
EG (pseudocode)
class parentObject():
parentVar = 1
# Create Child
x = childObject()
class childObject():
#Assign Var to the Var of the childs parent
childVar = parent.parentVar
>>> x.childVar = 1
is there a straitforward way to do this?
UPDATE:
I don't want to inheret the class, I need to be able to access the actual object that created it, as each object created from that class has different values.
Why not inherit the class?
class parentObject():
parentVar = 1
class childObject(parentObject):
childVar = parentObject.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you are going to have different instances of the class, you should do it as this instead:
class parentObject(object):
def __init__(self):
self.parentVar = 1
class childObject(parentObject):
def __init__(self):
super(childObject, self).__init__()
self.childVar = self.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you want a reference to the "parent" class, but inheritance is illogical, consider sending self in to the constructor:
class Room:
def __init__(self, name):
self.name = name
self.furniture = []
def add_chair(self):
self.furniture.append(Chair(self))
def __str__(self):
return '{} with {}'.format(self.name, self.furniture)
class Chair:
def __init__(self, room):
self.room = room
def __str__(self):
return 'Chair in {}'.format(self.room.name)
r = Room('Kitchen')
r.add_chair()
r.add_chair()
print r
print r.furniture[0]
Output:
Kitchen with [<__main__.Chair instance at 0x01F45F58>, <__main__.Chair instance at 0x01F45F80>]
Chair in Kitchen
Imagine the following class that displays some sort of hierarchy:
class BaseList2D(object):
def __init__(self):
self._superobject = None
self._subobjects = []
def InsertUnder(self, other):
if self not in other._subobjects:
other._subobjects.append(self)
self._superobject = other
return True
return False
def InsertAfter(self, other):
parent = other._superobject
if not parent:
return False
parent = parent._subobjects
parent.insert(parent.index(other) + 1, self)
return True
def GetDown(self):
if not len(self._subobjects):
return
return self._subobjects[0]
def GetNext(self):
if not self._superobject:
return
stree = self._superobject._subobjects
index = stree.index(self)
if index + 1 >= len(stree):
return
return stree[index + 1]
Is it really the best (or the only) way to set the superobject of other by accessing it's hidden attribute ? The attribute should not be set by the user ..
_foo is just a naming convention. Usually, there would be a property or something that sets the 'private' variable for you. If not, the convention is being (slightly) misused.