This is a heavily simplified version of what I am working on, I just don't want to put 5,000 lines in here. So I know this works and all, but I want to be able to have the method"eat" be able to be applied non-specifically to any object that this class parents (such as "John Smith", and adding lets say "Mike Doe".) I would like it to automatically select the person who undergoes ".eat()" to eat food rather than making the method specifically state: johnSmith.hunger = False. What I am doing is creating methods of actions people can use within the game that affect other objects (class children and variables), but I don't want to set a method for each action for each character unit. That would be insane. Given below is my set of code.
class human():
def __init__(self, name, hunger):
self.name = name
self.hunger = hunger
def eat(self):
johnSmith.hunger = False
print("Human Ate Food")
johnSmith = human("John Smith", True)
print("Human Is Hungry:", johnSmith.hunger)
johnSmith.eat()
print("Human Is Hungry:", johnSmith.hunger)
If I am unclear (which I know I am Not doing a great job explaining), feel free to ask.
Just use self:
def eat(self):
self.hunger = False
print("%s Ate Food" % self.name)
Related
I'm learning OOP in Python and I get stucked with one thing.
I have an example class:
class Animal:
def __init__(self, name="", hunger=0):
self.name = name
self.hunger = hunger
def eat(self):
self.hunger += 1
And some objects:
dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
I would like to use method eat() to change value of hunger in every single one of them at one blow. I have already tried to do something like this:
Animal.eat()
But it doesn't work (there's TypeError, because of missing argument 'self').
Also:
Animal.hunger += 1
Doesn't work (returns AttributeError).
If anyone has any ideas, I would be very grateful!
You can maintain a class variable that collects the instances and adjust all of their hungers in eat:
class Animal:
instances = []
def __init__(self, name="", hunger=0):
self.name = name
self.hunger = hunger
Animal.instances.append(self)
def eat(self):
for i in Animal.instances:
i.hunger += 1
Semantically, you might want to make it a classmethod, though
#classmethod
def eat(cls):
for i in cls.instances:
i.hunger += 1
You can still call it on instances if you so wish.
#schwobaseggi has the most straightforward answer for what you want to do, but what you want to do seems like it's asking for trouble. You have one class that does two very different things. Animal is an animal that has a name and eats, and it also keeps track of every animal instance and makes all of them eat. Animal is trying to do what individual animals do and also control a group of animals.
It might be better to split this into two different kinds of objects: An animal, and some sort of AnimalGroup like Zoo or Farm or Herd. The AnimalGroup class should be responsible for keeping track of a bunch of instances and make them all do stuff.
class AnimalGroup(object):
def __init__(self, animal_list):
self.animals = animal_list[:]
def add_animal(self, animal):
self.animals.append(animal)
def all_eat(self):
for animal in self.animals:
animal.eat()
then
dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
group = AnimalGroup([dog, cat, giraffe])
group.all_eat()
group.add_animal(Animal("pig"))
group.all_eat()
This separates out the responsibilities of each class and makes things much easier to change later on. You can now have different group behaviors without ever needing to change the animal class. You can have new animal classes that inherit from Animal and you don't need to worry about side effects. for example: class Mammal(Animal) . When I call Mammal.eat, will it update all animals? It might. class variables can be a bit tricky like that. Should it update all animals? No idea. With an AnimalGroup object, you don't need to worry.
You actually have to call it on the object itself like this:
cat.eat()
dog.eat()
giraffe.eat()
otherwise it doesn't know which object to actually change. You could store all your Objects in an array and loop over that array to call the function on all of them one after another:
dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
animals=[dog, cat, giraffe]
for animalType in animals:
animalType.eat()
now you can do them all at once or one at a time if you want. You will however need to addnew animals to the array after you create them to keep the list up to date:
fish=new Animal("fish")
animals.append(fish)
class Animal(object):
hunger = 0
def __init__(self, name=""):
self.name = name
def eat(self):
Animal.hunger = Animal.hunger + 1
dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
dog.eat()
print("Dog's hunger variable is", dog.hunger)
1
dog.eat()
print("Dog's hunger variable is :",dog.hunger)
2
print("Cat's hunger variable is :",cat.hunger)
2
print("Giraffe's hunger variable is :", giraffe.hunger)
2
When eat() is called on a single instance, the hunger variable is updated for all instances!
If you're wanting to do something on the class you have to declare it as a class variable:
class Animal:
hunger = 0
def __init__(self, name=""):
self.name = name
#classmethod
def eat(klass):
klass.hunger += 1
This way anytime you call Animal.eat() you'll be referencing the class method that modifies your class variable. You can still access the variable from within an Animal class with self.hunger but I would advise against that as it can get confusing coming back and trying to determine what's a class variable and what's a member variable.
To the best of my knowledge (and I really like OOP in python), the only way to do this is to create a new class with that specific attribute a.k.a.
class Animals:
def __init__(self, animals):
self.animals = animals
def all_eat(self):
for animal in animals:
animal.eat()
Then what you would have to do is:
dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
animals = Animals((dog, cat, giraffe))
animals.all_eat()
The reason for this is that python classes themselves do not have callable attributes so you have to call each instance of the class separately.
I am creating a text based adventure in python. I have ready two books on python and taken an online course, so I think I really have all the basics down.
Now I am creating my items currently. My setup is
Item->Weapon->(specific weapon here).
All classes inherit the previous.
I am unable to print the values of the items such as Holy_Sword and Stick. I am able to print them if I don't create them as classes and just use a variable to create the instance of weapon. However, due to what I want to do further down the line, I really would like them to be classes.
The error I am getting is:
unbound method str() must be called with Holy_Sword instance as first argument (got nothing instead)
My code is:
class Item(object):
def __init__(self, name, value, description):
self.name = name
self.value = value
self.description = description
def item_description(self):
return "Your %s is worth %d gold and is a %s" % (self.name, self.value, self.description)
class Weapon(Item):
def __init__(self,name, value,description, attack):
self.attack = attack
super(Weapon, self).__init__(name, value, description)
def __str__(self):
return "Your %s is worth %d gold and has an Attack Damage of %d, it is %s" % (self.name, self.value, self.attack, self.description)
class Stick(Weapon):
def __init__(self, name, value, description, attack):
super(Stick, self).__init__(name = "Stick", value= 1, description = "A stick...there may be potential here....or not.", attack = 1)
class Holy_Sword(Weapon):
def __init__(self, name, value, description, attack):
super(Holy_Sword, self).__init__(name = "The Holy Sword of Antioch", value= 20, description = "A Sword whose potential far outweighs it's lack of stylishness ", attack = 20)
class Sword(Weapon):
def __init__(self, name, value, description, attack):
super(Sword, self).__init__(name = "Sword", value= 3, description = "A Wooden Sword.", attack = 5)
print Holy_Sword.__str__()
Keep in mind that, in the code you have here, Holy_Sword refers to a class. It is not itself an instance of Item.
Holy_Sword.__str__ is an instance method. It can't be called on its own like you're trying to do here; it must be called through an instance of the Holy_Sword class.
(Note that it's usually better to not invoke __str__ directly. This method should usually only be called through the str() function, e.g. str(Holy_Sword).)
What you can do is create an instance of Holy_Sword and print the string value of that:
sword = Holy_Sword()
print str(sword)
However, you may want to instead consider making Holy_Sword be a instance of Weapon with specific attributes, rather than being a subclass. If the only way it needs to differ from other weapons is in its attributes, there's no need for it to be a separate class.
You need to instantiate the class first:
my_sword = Holy_sword(...)
print my_sword.__str__()
I am trying to make it so that when I can run a function which would populate a class with a couple of instances which are contained within the code.
class Pets(object):
def __init__(self, name, scientific_name, feet_number, type)
super(Pets,self).__init__()
self.name = name
self.scientific_name = scientific_name
self.feet_number = feet_number
self.type = type
This is the point where I get stuck.
I want to make a function which has a list of instances (Ex. a dog, a cat, a horse...) so that when the function is run those instances can be accessed immediately.
I know from places like Creating dynamically named variables from user input (Second Paragraph, First Sentence), that what I'm asking for is possible, I just don't know the syntax for it.
Is this what you are trying to do?
class Pet(object):
def __init__(self, details):
self.name = details[0]
self.scientific_name = details[1]
self.feet_number = details[2]
self.type = details[3]
if __name__ == '__main__':
pet_list = [('Cat', 'Kitty Cat', 4, 'Cuddly'), ('Dog', 'Puppy Wuppy', 3, 'Licky')]
pets = [Pet(item) for item in pet_list]
Which gives you:
pets
> [<__main__.Pet at 0x8134d30>, <__main__.Pet at 0x8134d68>]
pets[0]
> <__main__.Pet at 0x8134d30>
pets[0].name
> 'Cat'
pets[0].scientific_name
> 'Kitty Cat'
pets[1].name
> 'Dog'
There are a lot of ways this could be put together depending on what you want to do. For example, you could make a master class called Pet() with some basic attributes and methods that are true for all pets, then create specific classes for each pet that inherit the base class, e.g. class Cat(Pet):
Or you could give the Pet class the ability to know all the other details depending on what name is passed into it, then populate the instance variables accordingly.
A beginner level question.. trying to understand how I can best use the built-in unittest. In the trivial example below, the method consume_food picks a food item and then I am calling food.cut() method.
In future, this method may return instance of Drink object. The #commented code indicates one possible future implementation. In this case, self.milk will not have the cut method defined.
I want to add a unit test for consume_food and pick_food methods. I would like to do this for the original implementation first and then change it after adding self.milk functionality.
EDIT: The intention is to write a unit test for an existing api, so that I can capture any such changes ( i.e. absence of Drink.cut method) forcing me to update the methods and unit tests.
Can someone please help showing me how to write a unit test for this example?
class Fruit:
def cut(self):
print("cut the fruit")
class Drink:
def pour(self):
print("pour the drink")
class A:
def __init__(self):
self.apple = Fruit()
self.banana=Fruit()
#self.milk = Drink()
#self.liquid_diet = True
def consume_food(self):
food = pick_food()
food.cut()
print("consuming the food")
def pick_food(self):
return self.apple
#if self.liquid_diet: return self.milk
#return self.apple
The thing is, your cut() and consume_food() methods don't really do much right now that allow you to make meaningful assertions after you execute them in a test.
So I'd suggest to expand your initial code a little bit to have those methods act upon the respective objects so that you can make meaningful assertions on their state after invoking those methods.
Right now, all they really do is write to STDOUT, which is sort of a global state - which should generally be avoided and is always difficult to test. (I'm not saying that printing output is a bad thing - but if that's the only thing your code does, it's going to be very tricky to test).
So I introduced a common superclass Food which has a consume() method, and sets a corresponding attribute. Similarly, the cut() method on Fruit now sets an attribute that you can test for.
import unittest
class Food(object):
def __init__(self):
self.consumed = False
def consume(self):
self.consumed = True
class Fruit(Food):
def __init__(self):
super(Fruit, self).__init__()
self.been_cut = False
def cut(self):
print("cut the fruit")
self.been_cut = True
class Consumer(object):
def __init__(self):
self.apple = Fruit()
self.banana = Fruit()
def consume_food(self):
food = self.pick_food()
food.cut()
print("consuming the food")
food.consume()
def pick_food(self):
return self.apple
These tests now can make assertions on the object's states after the relevant methods have been invoked. Note that they follow the AAA pattern - Arrange Act Assert:
First, you arrange the objects under test the way you need them (instantiate a consumer).
Then you act on the objects under test (invoking the method in question)
Finally, you make assertions on the resulting state you expect the objects to be in
class TestConsumer(unittest.TestCase):
def test_consume_food_consumes_the_apple(self):
c = Consumer()
c.consume_food()
self.assertTrue(c.apple.consumed,
"Expected apple to be consumed")
def test_consume_food_cuts_the_food(self):
c = Consumer()
c.consume_food()
self.assertTrue(c.apple.been_cut,
"Expected apple to be cut")
def test_pick_food_always_selects_the_apple(self):
c = Consumer()
food = c.pick_food()
self.assertEquals(c.apple, food,
"Expected apple to have been picked")
if __name__ == '__main__':
unittest.main()
For a program that creates a timetable for a doctor(specialist) I want to use certain attributes of an object created by a different class to be used in the class that makes the timetable for the doctor.
class makePatient(object):
def __init__(self,name,room):
self.name = name
self.room = room
def getPatient(self):
print(self.name)
print(self.room)
class makeSpecialist(object):
def __init__(self,name,specialization,timetable):
self.name = name
self.specialization = specialization
self.timetable = timetable
def getSpecialist(self):
print(self.name)
print(self.specialization)
print(self.timetable)
class makeAgenda(object):
def addAgenda(self):
self.timetable.append()
#I want to append the name of the patient I have defined here.
print(self.timetable)
patient1 = makePatient("Michael","101")
specialist1 = makeSpecialist("Dr. John","Hematology",[])
What do I do now, to make sure that the name "Michael" gets added to the list [] of specialist Dr. John?
Thanks in advance, I will provide further details if necessary!
I think another approach would be better; you can put the whole makePatient object into the timetable for the specialist:
specialist1 = makeSpecialist("Dr. John", "Hematology", [patient1])
Now you can access the names and other attributes of the patients in a specialist's timetable:
for patient in specialist1.timetable:
print(patient.name)
You can also define a __repr__ method to tell Python how to display an object, rather than the current getPatient:
class makePatient(object):
# ...
def __repr__(self):
return "{0} (room {1})".format(self.name, self.room)
Now when you print the whole timetable:
>>> print(specialist1.timetable)
You get the necessary information:
[Michael (room 101)]
Note also that the classes should probably be called, simply, Patient, Specialist and Agenda; the make is implied.
Finally, you will get errors in makeAgenda.addAgenda as, without an __init__, self.timetable doesn't exist for a makeAgenda object, and an empty append() doesn't do anything anyway.
Classes are often used to represent entities and operations allowed on them, include constructing, or making, new instances of them. Therefore, your classes would be better named simplyPatient, Specialist, andAgenda. The name of the method that constructs a new instance of any class in Python is always__init__().
That said, after creating aPatientand aSpecialistyou could then add patient instances to the specialist's timetable/agenda by passing it to aSpecialistmethod specifically designed for that purpose. In other words, a Specialist "has-a" Agenda instance namedtimetableand to which patients can be added via an appropriately namedadd_to_timetable()method.
Here's what I mean -- note I've modified your code to follow PEP 8 -- Style Guide for Python Code guidelines which I also suggest that you follow:
class Agenda(object):
def __init__(self):
self.events = []
def append(self, event):
self.events.append(event)
class Patient(object):
def __init__(self, name, room):
self.name = name
self.room = room
def get_patient(self):
print(self.name)
print(self.room)
class Specialist(object):
def __init__(self, name, specialization):
self.name = name
self.specialization = specialization
self.timetable = Agenda()
def add_to_timetable(self, patient):
self.timetable.append(patient)
def get_specialist(self):
print(self.name)
print(self.specialization)
print(self.timetable)
specialist1 = Specialist("Dr. John", "Hematology")
patient1 = Patient("Michael", "101")
specialist1.add_to_timetable(patient1)
I'm not too sure what you're trying to accomplish here with method that just print values or with the makeAgenda class, but here's how you can get Michael in Dr. John's list:
specialist1.timetable.append(patient1.name)