We need a way for our Tribute object to reduce their hunger. Create a method eat(food), which takes in a Food object. It will reduce the hunger of the player by the food.get food value(). If object that's passed to the eat method is of the type Medicine, it will increment the player’s health by medicine.get medicine value().
Pre-defined code:
class Tribute(Person):
def reduce_hunger(self, hunger):
self.hunger = self.hunger - hunger
if self.hunger < 0:
self.hunger = 0
else:
return self.hunger
class Thing(MobileObject):
def __init__(self, name):
super().__init__(name, None)
self.owner = None
def set_owner(self, owner):
self.owner = owner
def get_owner(self):
return self.owner
def is_owned(self):
return self.owner is not None
class Person(LivingThing):
def take(self, thing):
# Can only take things in current location and not owned by others
if isinstance(thing, Thing) and thing in self.place.objects and not thing.is_owned():
thing.set_owner(self)
self.inventory.append(thing)
self.place.del_object(thing)
GAME_LOGGER.add_event("TOOK", self, thing)
else:
GAME_LOGGER.warning("{} cannot take {}.".format(self.get_name(), thing.get_name()))
def named_col(col):
# Only accepts tuple/list
type_col = type(col)
if type_col != list and type_col != tuple:
return None
return type_col(map(lambda x: x.get_name() if isinstance(x, NamedObject) else x, col))
class Food(Thing):
def __init__(self, name, food_value):
self.name = name
self.food_value = food_value
def get_food_value(self):
return self.food_value
class Medicine(Food):
def __init__(self, name, food_value, medicine_value):
super().__init__(name, food_value)
self.medicine_value = medicine_value
def get_medicine_value(self):
return self.medicine_value
class MobileObject(NamedObject):
def __init__(self, name, place):
super().__init__(name)
self.place = place
def get_place(self):
return self.place
This is my code:
def eat(self, food):
if food in self.get_inventory():
self.inventory.remove(food) # not self.inventory = self.inventory.remove(food) cos self.inventory is a list. if use = it wont return anything
self.reduce_hunger(food.get_food_value())
if isinstance(self, medicine):
self.health = self.health + food.get_medicine_value()
if self.health > 100:
self.health = 100
elif self.health <0:
self.health = 0
To test my code:
cc = Tribute("Chee Chin", 100)
chicken = Food("chicken", 5)
cc.take(chicken) # Chee Chin took chicken
cc.take(aloe_vera) # Chee Chin took aloe vera
print(named_col(cc.get_inventory())) # ['chicken', 'aloe vera']
i got this error:
AttributeError: 'Food' object has no attribute 'owner'
instead of the expected output 'Chee Chin took chicken'.
What's wrong with my code?
Food is a subclass of Thing but Food's __init__ doesn't call Thing's __init__. That is the source of the problem. Food's __init__ needs the following line at its start:
super().__init__(name)
Related
In my program I have the following question. How can I define a method in the class 'Mouse' 'Keyboard' and 'Screen' so that they return the room and the computer they belong to + the associated attribute of the class (so for the keyboard class this would be: 'The computer {} is located in the room {} and has the language {} ') Can someone tell me how I can define such a method for these 3 classes without changing the program itself? The method should be defined for each class seperated. The exact task is "Extend the output of maus, screen and tastatur so that the user knows which computer in which room they belong".
I've tried to define the following method:
def as_text(self):
return "{} an {} in {}".format(self.__name, self.__computer, self.__computer.__room)
In my three classes I have build in a reference to computer. My Class Computer has a reference to room, so I've tried to call it with self.__computer.__room but that doesn't work and I'm not sure how to call this attribute.
Here is my code:
class Room:
__name = "unknown"
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
class Device:
__name = "Device"
def __init__(self, name):
self.__name = name
def as_text(self):
return "%s" % (self.__name)
class Computer(Device):
__ip = "unknown"
def __init__(self, name, ip, room):
super().__init__(name)
self.__ip = ip
self.__room = room
def as_text(self):
return "%s with ip=%s" % (super().as_text(), self.__ip)
class Laptop(Computer):
def __init__(self, name, room, ip, with_case = True):
super().__init__(name, room, ip)
self.__with_case = with_case
def as_text(self):
if (self.__with_case):
return "%s with case" % super().as_text()
else:
return super().as_text()
class Screen(Device):
__width = "1920"
__height = "1080"
def __init__(self, name, width, height, computer):
super().__init__(name)
self.__width = width
self.__height = height
self.__computer = computer
def as_text(self):
return "{} an {}".format(self.__name, self.__computer)
class Tastatur(Device):
__language = 'English'
def __init__(self, name, language, computer):
super().__init__(name)
self.__language = language
self.__computer = computer
class Maus(Device):
__type = 'Gaming Mouse'
def __init__(self, name, type, computer):
super().__init__(name)
self.__type = type
self.__computer = computer
Your request is not particularly clear, here what I got.
This is my method for the Screen Class:
def as_text(self):
return "{} an {} in {}".format(super().as_text(), self.__computer.as_text(), self.__computer.display_room())
super().as_text()
This calls the method as_text from the parent class Device.
self.__computer.as_text()
This calls the as_text() method from an instance of the Computer class, which is an attribute of your class Screen.
self.__computer.display_room()
This calls the method display_room() from the Computer class, I created it and returns the Room's name.
def display_room(self):
return self.__room.get_name()
Now you should be able to write methods for Tastur and Maus yourself.
I got a program from my professor where I had to do some tasks. Since we're currently learning "inheritance with classes", I'm not that good at it yet. We had been given a task where it says "Extend the output of mouse, screen and keyboard so that the user knows which computer in which room they belong to". I did this, but I'm not sure if it's true or if there is a better solution. Can anyone explain to me whether the whole thing can be solved better and if so, why? I have defined a method in each class where I get this as an output, but is there a better way where I only have to define a method once and this applies to all other classes? Thanks in advance
Here is my code:
class Room:
__name = "unknown"
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
class Device:
__name = "Device"
def __init__(self, name):
self.__name = name
def as_text(self):
return "%s" % (self.__name)
class Computer(Device):
__ip = "unknown"
def __init__(self, name, ip, room):
super().__init__(name)
self.__ip = ip
self.__room = room
def as_text(self):
return "%s with ip=%s" % (super().as_text(), self.__ip)
class Laptop(Computer):
def __init__(self, name, room, ip, with_case = True):
super().__init__(name, room, ip)
self.__with_case = with_case
def as_text(self):
if (self.__with_case):
return "%s with case" % super().as_text()
else:
return super().as_text()
class Screen(Device):
__width = "1920"
__height = "1080"
def __init__(self, name, room, width, height, computer):
super().__init__(name)
self.__room = room
self.__width = width
self.__height = height
self.__computer = computer
def as_text(self):
return "%s with resolution %dx%d" % (super().as_text(), self.__width, self.__height)
def screen_location_computer(self):
return 'The screen with the height {} and width {} is located in Room {} and belongs to the computer {}'.format(self.__height, self.__width , self.__room.get_name(), self.__computer)
class Keyboard(Device):
__language = 'English'
def __init__(self, name, room, language, computer):
super().__init__(name, room)
self.__language = language
self.__computer = computer
def keyboard_location_computer(self):
return 'The keyboard with the language {] is located in Room {} and belongs to the computer {}'.format(self.__language, self.__room.get_name(), self.__computer)
class Mouse(Device):
__type = 'Gaming Mouse'
def __init__(self, name, room, type, computer):
super().__init__(name, room)
self.__type = type
self.__computer = computer
def mouse_location_computer(self):
return 'The mouse with the type {] is located in Room {} and belongs to the computer {}'.format(self.__type, self.__room.get_name(), self.__computer)
You should try to regroup all common attributes and methods in the super class and leave only the specialized attributes in the subclasses, this way you can minimize the need of methods and arguments.
Idem for the method I renamed 'description' : one part is common to all instances (the end) while another (the beginning) is specific. Let super handle the common part and pass it the specialized part to assemble the whole string.
(I removed some classes and attributes for the simplicity of the example)
class Device():
__computer = None
__name = None
__room = None
def __init__(self, name, computer, room):
self.__name = name
self.__computer = computer
self.__room = room
def room(self):
return self.__room
def name(self):
return self.__name
def description(self, str):
return '{} is located in Room "{}" and belongs to the computer "{}"'.format(str, self.__room, self.__computer.name())
class Computer(Device):
def __init__(self, name, room):
super().__init__(name, self, room)
class Screen(Device):
__width = "1920"
__height = "1080"
def __init__(self, name, computer, width, height):
super().__init__(name, computer, computer.room())
self.__width = width
self.__height = height
def description(self):
return super().description('The screen with the height {} and width {}'.format(self.__height, self.__width))
class Mouse(Device):
__type = 'Gaming Mouse'
def __init__(self, name, computer, type):
super().__init__(name, computer, computer.room())
self.__type = type
def description(self):
return super().description('The mouse with the type {}'.format(self.__type))
cpt = Computer("Acer", "Classroom 12")
cpt2 = Computer("iMac 15", "Classroom 38")
screen = Screen("27 inch", cpt2, 1920, 1080)
mouse = Mouse("Mouse", cpt, "Gaming")
print (screen.description())
print (mouse.description())
Should you need it, the tutorial I am following is Python Programming by #Derek Banas:
This lesson is demonstrating class object inheritance
class Animal:
__name = ""
__height = 0
__weight = 0
__sound = 0
def __init__(self, name, height, weight, sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def get_type(self):
print("Animal")
def toString(self):
return "{} is {} cm tall and {} kilograms and {}".format(self.__name,
self.__height,
self.__weight,
self.__sound)
cat = Animal('Whiskers', 33, 10, 'Meow')
print(cat.toString())
class Dog(Animal):
__owner = ""
def __init__(self, name, height, weight, sound, owner):
self.__owner = owner
super(Dog, self).__init__(name, height, weight, sound)
def set_owner(self, owner):
self.__owner = owner
def get_owner(self):
return self.__owner
def get_type(self):
print("Dog")
def toString(self):
return "{} is {} cm tall & {} kgrms and {} hi
{}".format(self.get_name(),
self.get_height(),
self.get_weight(),
self.get_sound(),
self.get_owner())
""" I am getting this runtime error message python version 3.6
Here is the error:
File "C:/Watson/HDM/tutorial_py1.py", line 192, in toString
self.get_height(),
AttributeError: 'Dog' object has no attribute 'get_height' """
Dog object is not having any attribute 'get_height' as get_height() function is not declared in the class before. You need to add the method in the class:
def get_height(self, name):
return self.__height
I am supposed to create a class called Dog(Animal) which is inheriting from Class Animal. However after I run this code, I got errors that I do not understand:
The problem is solved, no further questions that I see at the moment
class Animal:
__name = ""
__height = 0
__weight = 0
__sound = 0
def __init__(self, name, height, weight, sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
#def set_name(self, name):
#self.__name = name
def get_name(self):
return self.__name
def get_height(self):
return str(self.__height)
def get_weight(self):
return str(self.__weight)
def get_sound(self):
return self.__sound
def get_type(self):
print("Animal")
def toString(self):
return "{} is {} cm tall and {} kilograms and says{}".format(self.__name,
self.__height,
self.__weight,
self.__sound)
cat = Animal('pussy', 33, 10, 'meow')
print(cat.toString())
print(cat.get_type())
print(cat.get_sound())
class Dog(Animal):
__owner = ""
def __init__(self, name, height, weight, sound, owner):
self.__owner = owner
super(Dog, self).__init__(name, height, weight, sound)
def set_owner(self, owner):
self.__owner = owner
def get_owner(self):
return self.__owner
def get_type(self):
print("Dog") # Dog object
def toString(self):
return "{} is {} cm tall and {} kilograms and says{} its owner is {}".format(self.__name,
self.__height,
self.__weight,
self.__sound,
self.__owner)
spot = Dog("kaili", 22, 33, "woof", "Jiahui")
print(spot.toString())
Change this line:
class Animal:
to this:
class Animal(object):
This post explains it quite well.
After I added metaclass = type at the beginning, the problem is solved. I am not quite sure but seems the metaclass allows python2.7 to access python3's library.
In the Person object, there is already a support for an inventory, and when the Person object takes a Weapon object or Food object, the object would go to the inventory. For the Tribute object, I want to retrieve the Weapon objects from the inventory by creating a new method in the Tribute class, get_weapons(), which would return a tuple of Weapon objects that the Tribute currently has in his inventory.
class Tribute(Person):
...
def get_weapons(self):
self.weapons=[]
for item in self.get_inventory():
if isinstance(item,Weapon):
self.weapons.append(item)
return tuple(self.weapons)
cc = Tribute("Chee Chin", 100)
chicken = Food("chicken", 5)
aloe_vera = Medicine("aloe vera", 2, 5)
bow = RangedWeapon("bow", 4, 10)
sword = Weapon("sword", 2, 5)
Base = Place("base")
Base.add_object(cc)
Base.add_object(chicken)
Base.add_object(aloe_vera)
Base.add_object(bow)
Base.add_object(sword)
cc.take(bow) # Chee Chin took bow
cc.take(sword) # Chee Chin took sword
cc.take(chicken) # Chee Chin took chicken
cc.take(aloe_vera) # Chee Chin took aloe_vera
But I keep getting AttributeError: 'RangedWeapon' object has no attribute 'owner'. I'm not sure what went wrong. I would really appreciate some help. Thank you!
import random
from collections import OrderedDict
######################
# Class: NamedObject #
######################
class NamedObject(object):
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
#######################
# Class: MobileObject #
#######################
class MobileObject(NamedObject):
def __init__(self, name, place):
super().__init__(name)
self.place = place
def get_place(self):
return self.place
################
# Class: Thing #
################
class Thing(MobileObject):
def __init__(self, name):
super().__init__(name, None)
self.owner = None
def set_owner(self, owner):
self.owner = owner
def get_owner(self):
return self.owner
def is_owned(self):
return self.owner is not None
#################
# Class: Person #
#################
class Person(LivingThing):
def __init__(self, name, health, threshold):
self.inventory = []
super().__init__(name, health, threshold)
def take(self, thing):
# Can only take things in current location and not owned by others
if isinstance(thing, Thing) and thing in self.place.objects and not thing.is_owned():
thing.set_owner(self)
self.inventory.append(thing)
self.place.del_object(thing)
GAME_LOGGER.add_event("TOOK", self, thing)
else:
GAME_LOGGER.warning("{} cannot take {}.".format(self.get_name(), thing.get_name()))
def remove_item(self, thing):
#Can only remove things in inventory
if isinstance(thing, Thing) and thing in self.get_inventory() and thing.get_owner()==self:
thing.set_owner(None)
self.inventory.remove(thing)
else:
GAME_LOGGER.warning("{} does not own {}.".format(self.get_name(), thing.get_name()))
def go(self, direction):
new_place = self.place.get_neighbor_at(direction.upper())
if new_place is not None:
self.move_to(new_place)
else:
GAME_LOGGER.warning("{} cannot go {} from {}".format(self.get_name(), direction, self.get_place().get_name()))
def get_inventory(self):
return list(self.inventory)
def objects_around(self):
return list(filter(lambda t: t is not self, self.get_place().get_objects()))
def get_exits(self):
return self.get_place().get_exits()`
class Weapon(Thing):
def __init__(self, name, min_dmg, max_dmg):
self.name=name
self.min_dmg=min_dmg
self.max_dmg=max_dmg
def min_damage(self):
return self.min_dmg
def max_damage(self):
return self.max_dmg
def damage(self):
return random.randint(self.min_dmg,self.max_dmg)
class RangedWeapon(Weapon):
def __init__(self, name, min_dmg, max_dmg):
super().__init__(name, min_dmg, max_dmg)
self.shots=0
def shots_left(self):
return self.shots
def load(self, ammo):
if ammo.weapon_type()==self.name:
self.shots+=ammo.get_quantity()
ammo.remove_all()
def damage(self):
if self.shots==0:
return 0
else:
self.shots-=1
return super().damage()
not an expert on python 3.x, but:
class Weapon(Thing):
def __init__(self, name, min_dmg, max_dmg):
self.name=name
self.min_dmg=min_dmg
self.max_dmg=max_dmg
you never actually set Weapon to inherit from Thing - you need to call the super().__init__ line that's appropriate for Thing, in Weapon's ctor. its an annoying python quirk.
have a look here - at RangedWeapon's ctor - you're doing it right:
super().__init__(name, min_dmg, max_dmg)