[Tutor] Class methods
Alan Gauld
alan.gauld at btinternet.com
Thu Jun 23 03:38:29 CEST 2011
"David Merrick" <merrickdav at gmail.com> wrote
> Can someone show me how to code this correctly please?
We've been doing that but you are still making
some very basic mistakes which reflect a deep
misunderastanding of what you are doing. You
really should take several steps back and review
the use of variables and functions and then
reread the introductory material on classes
and objects. Until you get the basics right you
will struggle and even if somebody fixes all the
issues in this code, the minute you try another
program all the same problems will bite you.
That having been said I'll make some comments:
> class Critter(object):
>
> """A virtual pet"""
> def __init__(self, name, hunger = 0, boredom = 0):
> self.name = name
> self.hunger = hunger
> self.boredom = boredom
This is OK.
> # __ denotes private method
> def __pass_time(self):
> self.hunger += 1
> self.boredom += 1
> self.__str__()
The last line does nothing useful. (It prints stuff just now
but that's because of a conceptual fault in your str method.
What you should really be saying here is:
print (self)
> def __str__(self):
> print("Hunger is",self.hunger, "Boredom is " ,self.boredom)
> print("Unhappines is ",self.hunger + self.boredom," and Mood
> is
> ",self.mood)
__str__ methods are supposed to return a string which
can be used (or printed) by other code. They should not
print anything themselves.
This should do something like:
return """Hunger is %s,
Boredom is %s
Unhappines is %s and
Mood is%s""" % ( self.hunger,
self.boredom,
self.hunger+self.boredom,
self.mood)
> @property
> def mood(self):
> unhappiness = self.hunger + self.boredom
> if unhappiness < 5:
> m = "happy"
> elif 5 <= unhappiness <= 10:
> m = "okay"
> elif 11 <= unhappiness <= 15:
> m = "frustrated"
> else:
> m = "mad"
> return m
OK
> def talk(self):
> for critter in farmlet:
> print("I'm", self.name, "and I feel", self.mood,
> "now.\n")
> self.__pass_time()
Problem: What is farmlet here? There is no farmlet in
the method. There is no self.farmlet you can access.
So now your class is tied to the external farmlet variable
in the global scope, making your class pretty much useless
in any other context. Also it will print the same message
as many times as there are critters in farmlet - 2 in this case.
But the message won't change because self still only
applies to the current object.
You are iterating over the critters in your main() function,
you don't need to do it inside the critter itself. Each critter
should only comment on its own state.
I'd also prefer that this returned a string too because
putting print statements inside methods limits the usefulness
of the class. How would it work in a GUI version for example?
Better to return a string and print that where you call it.
> def eat(self):
> food = int(input("Enter how much food you want to feed your
> critter:
> "))
> print("Brruppp. Thank you.")
> self.hunger -= food
> # hunger = 0 at iniatition
> # self.hunger = self.boredom - food
> if self.hunger < 0:
> self.hunger = 0
> self.__pass_time()
OK, I think
> def play(self):
> fun = int(input("Enter how much fun you want your critter to
> have:
> "))
> print("Wheee!")
> self.boredom -= fun
> # boredom = 0 at iniatition
> # self.boredom = self.boredom - fun
> if self.boredom < 0:
> self.boredom = 0
> self.__pass_time()
OK, I think
> def main():
> crit1 = Critter("Sweetie")
> crit2 = Critter("Dave")
> farmlet = [crit1,crit2]
OK so far, we have a list with two Critters
> choice = None
> while choice != "0":
> print \
> ("""
> Critter Caretaker
>
> 0 - Quit
> 1 - Listen to your critter
> 2 - Feed your critter
> 3 - Play with your critter
> """)
>
> choice = input("Choice: ")
> print()
Also OK we now have a choice and a loop.
> if choice == "0":
> print("Good-bye.")
And we exit so the program eventually stops,
which is good.
> elif choice == "1":
> for critter in farmlet:
> farmlet.talk()
But here we are asking the list to do stuiff which
is not good. It is the critters that talk. So you need
to send talk() to the critter not the list:
for critter in farmlet:
critter.talk()
> # feed your critter
> elif choice == "2":
> farmlet.eat()
Again lists can't eat, you need to feed weither an
individual crittter - get the user to choose which?
- or feed all your critters using the same code
pattern as for talk above.
> # play with your critter
> elif choice == "3":
> f.play(farmlet)
You don't have an f and you don't now have a
play method or function that takes a farmlet
as an argument. Again you need the same
pattern as above, call the play() method of
each critter in farmlet, or choose a critter to
play with.
> # some unknown choice
> else:
> print("\nSorry, but", choice, "isn't a valid choice.")
> Traceback (most recent call last):
> File "I:/Python/programs/critter_farm4.py", line 117, in <module>
> main()
> File "I:/Python/programs/critter_farm4.py", line 103, in main
> farmlet.talk()
> AttributeError: 'list' object has no attribute 'talk'
See the comments above. You really need to think
about the type of each variable you are using and
what operations it supports. farmlet is a list. lists
don't talk.
HTH,
--
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/
More information about the Tutor
mailing list