Basically, The user creates a creature by giving it a name, this name is then fed into the creation of the creature, where it is then given stats (This all works fine, even when making several creatures). However, I want to give the option to the user to check the stats of the creature they created through the 'check_stats()' function, they do this by inputting the slot number of the creature in their line-up, the code then finds the name of the creature through this, and calls the check_stat function using it. However this does not work as I receive the error:
AttributeError: 'str' object has no attribute 'check_stats'
If i create the creature manually in the code, like I write:
Bill = Pet('Bill')
It works perfectly and i can call the stats whenever. Its just when the user creates the class instance, it does not work.
This is my code (That is the problem):
def create_creature():
creature = Pet(name)
creature.create_stats()
print(" \n \n \n")
minions = {}
minion_value = {
1: None,
2: None,
3: None,
4: None,
5: None,
6: None
}
minion_slot = 0
for value in range(2):
name = input("Create a pet!\n> ")
minions[name] = create_creature()
minion_slot = 1
minion_value.update({minion_slot : name})
print("Your line-up")
for creature_ in minion_value:
print("{}: {}".format(creature_, minion_value[creature_]))
check_creature = int(input("Which pet would you like to check? (number)\n> "))
for creature_ in minion_value:
if check_creature == creature_:
(minion_value[check_creature]).check_stats()
This is what the output of this code looks like:
Create a pet!
> Bob
---Bob---
3 years old
5% healthy
66% happy
65% crazy
48% smarts
Create a pet!
> Bill
---Bill---
9 years old
100% healthy
35% happy
93% crazy
13% smarts
Your line-up
1: Bob
2: Bill
3: None
4: None
5: None
6: None
Which pet would you like to check? (number)
> 1
Traceback (most recent call last):
File "C:\Users\c10ld\Downloads\Test_class_animals.py", line 103, in <module>
(minion_value[check_creature]).check_stats()
AttributeError: 'str' object has no attribute 'check_stats'
This is what it should look like:
Create a pet!
> Bob
---Bob---
3 years old
5% healthy
66% happy
65% crazy
48% smarts
Create a pet!
> Bill
---Bill---
9 years old
100% healthy
35% happy
93% crazy
13% smarts
Your line-up
1: Bob
2: Bill
3: None
4: None
5: None
6: None
Which pet would you like to check? (number)
> 1
Your Pet:
---Bob---
3 years old
5% healthy
66% happy
65% crazy
48% smarts
Can anyone help me? Thank you! (Sorry if this is too long, its my first post and i wanted to make sure there was little to no confusion.)
EDIT: Here is the rest of the code, including the Pet class:
import random
class Animal(object):
def __init__(self, age, health, happiness):
self.age = 0
self.health = 0
self.happiness = 0
def get_age(self):
self.age = random.randint(8, 100)
def get_health(self):
self.health = random.randint(1, 100)
print(f"{self.health}% healthy")
def get_happiness(self):
self.happiness = random.randint(1, 100)
print(f"{self.happiness}% happy")
def age_up(self):
self.age = 1
print(f"{int(round(self.age, 0))} years old")
if self.age < 17:
self.age_up()
elif self.age >= 17:
print("died of age.")
class Pet(Animal):
def __init__(self, name):
self.name = name
self.craziness = 0
self.intelligence = 0
def pet_age(self):
self.get_age()
self.age = self.age / 7
print(f"{int(round(self.age, 0))} years old ")
def get_craziness(self):
self.craziness = random.randint(1,100)
print(f"{self.craziness}% crazy")
def get_intelligence(self):
self.intelligence = random.randint(1, 100)
print(f"{self.intelligence}% smarts")
def create_stats(self):
print(f"---{self.name}---")
self.pet_age()
self.get_health()
self.get_happiness()
self.get_craziness()
self.get_intelligence()
def check_stats(self):
print(f"---{self.name}---")
print(f"{int(round(self.age, 0))} years old")
print(f"{self.health}% healthy")
print(f"{self.happiness}% happy")
print(f"{self.craziness}% crazy")
print(f"{self.intelligence}% smarts")
I created an 'Animal' class as i was planning on creating more sub-classes, such as workers and warriors!
CodePudding user response:
It seems you are storing just the name of the creature in your minion_value
dictionary. This is why (minion_value[check_creature])
from
check_creature = int(input("Which pet would you like to check? (number)\n> "))
for creature_ in minion_value:
if check_creature == creature_:
(minion_value[check_creature]).check_stats()
is returning a str
which has no check_stats method defined from your custom Pet
class.
So, we can do this.
for value in range(2):
name = input("Create a pet!\n> ")
minions[name] = create_creature(name)
minion_value.append(minions[name])
and for the create_creature
function,
def create_creature(name: str) -> Pet:
creature = Pet(name)
creature.create_stats()
print(" \n \n \n")
return creature
Thank you for providing further code! Let's see..
class Pet(Animal):
...(after __init__)...
def __str__(self):
return self.name # it's that simple :)
I checked the documentation and __repr__
is for more technical representations whereas __str__
is for the end user, like the player.
We can also add getter and setter decorators to the code for more elegance. I'll add that soon too!
To improve readability and reduce memory usage, we can also use a list instead a dictionary for the minion_value
object. Edit: Thank you for your reply. I changed the for loop code above for reference.
And as others have suggested, it is wise to constrain global variables and pass necessary arguments as a parameter to a function. Edit: Great you stuck with it! I'm glad it worked as you intended.
Thank you for your question, and your game looks really fun!
Edit: As we changed the minion_value
to be an empty list minion_value = []
, we should change the line_up
code as well. f-strings
are a useful toolkit for formatting. see here
print("Your line-up")
for i, creature_ in enumerate(minion_value):
print(f"{i}: {creature_}")
or
print("Your line-up")
for i in range(1, 7):
try:
print(f"{i}: {minion_value[i]}")
except IndexError:
print(f"{i}: None")
CodePudding user response:
You need to pass the variable as an argument:
Random example (you should be able to apply the same logic to your code):
class Person(object):
def __init__(self, name):
self.name = name
my_name = input("What is your name? ")
p = Person(my_name)
print(p.name)
Output:
What is your name?
Ryan
Ryan
CodePudding user response:
There are many things wrong with the code here.
Firstly, create_creature
does not return anything, which in Python means return None
, so I don't think you know what you meant to store in minions when you do minions[name] = create_creature()
.
Then, create_creature
also appears to be using a name
variable, which is not assigned in it or given as argument, so where does the name come from ?
Then, the minion_value
is a dict with integer keys from 1 to 7, that looks like a list to me.
Finally, you are storing name
in minion_value
which must be a str rather than a Pet, and so that is why you get the attribute error for missing .check_stats()
, which is defined for Pet
but not str
.