BradTheBrutalitist BradTheBrutalitist - 5 months ago 8
Python Question

How Do I Fix My Code So It Can print() Out The Results I Want?

Note: I'm not looking for you to remake my code, I'm looking for tips and links to sites that will help me improve this code. If you want to fix the code I will also accept your answer.

I'm trying to understand how

class
works but, I'm having a really hard time doing so. I made a
class
called
Stat
which contains all of the stats for a given user. All of the stats for the user are,
name, level, totexp and role
. each
role
has 3 stats (it should have three but, my code is messed up),
health, attack, and defense
. Here is the main code (not working):

class Stat():
def __init__(self, name, level, totexp, role, health, attack, defense):
self.name = Name
self.level = 1
self.totexp = 0
self.role = Role
self.health = health
self.attack = attack
self.defense = defense
self.exp = 0
def choose_name():
while(True):
Name = input("What is your Dicer's name?:\n").title()
if(any(Bad_Words in Name.lower() for Bad_Words in [])):
print("That's an inappropriate name! Try again")
elif(len(Name) < 3):
print("That name is too short! Try again.")
elif(len(Name) > 16):
print("That name is too long! Try again.")
else:
break
def choose_role():
Roles = {
'mage':lambda:Role(100, 40, 10), #(Health, Attack, Defense)
'warrior':lambda:Role(100, 30, 20),
'gunner':lambda:Role(100, 20, 30),
'archer':lambda:Role(100, 10, 40)
}
while(True):
Role = input("What role do you want to be?\nChoices:\n1. Mage\n"
"2. Warrior\n3. Gunner\n4. Archer\n").title()
if(Role.lower() in (Roles)):
return
else:
print("That's not a role! Try again.")
self = choose_name()
self = choose_role()


After the main code the
Results
(Like in the title) or the result code should
print
out the
Stats
accordingly to the order of the instances. Here is the result code:

print("Here is your Dicer's information:\nDicer's name: {0}\n"
"Level: {1}\nExperience: {2}\nRole: {3}\nRole Stats:\n"
"Health: {4}\nAttack: {5}\nDefense: {6}".format(self.name, self.level,
self.totexp, self.role,
self.health, self.attack,
self.defense))


When I run the code I get an error:

Traceback (most recent call last):
File "python", line 37, in <module>
AttributeError: 'NoneType' object has no attribute 'name'


I think I have ideas to why this is happening but I don't know how to fix it. Can you help me with where I need to start on with my code and ways to fix it. Here is the results I wanted (For this example the Name = Bob and Role = Gunner):

Dicer's name: Bob
Level: 1
Experience: 0
Role: Gunner
Role Stats:
Health: 100
Attack: 20
Defense: 30

Answer

I'm a little hesitant to post this because the code is a giant mess. But you said you didn't want a re-write you just wanted to see your code fixed, so here it is fixed. I've commented everything I changed

#renamed stat to player, the point of the object shouldn't be to hold just the stats, should hold all information
#pertaining to the player / dicer
class Dicer():
    #levelm, totalexp, health removed from constructor
    def __init__(self, name, role, health, attack, defense):
        self.name = name #changed Name to name
        self.level = 1
        self.totexp = 0
        self.role = role #changed Role to role
        self.health = health
        self.attack = attack
        self.defense = defense
        self.exp = 0

    #instance function to print the stats of the dicer
    def print_info(self):
        print(
            "Here is your Dicer's information:\nDicer's name: {0}\nLevel: {1}\nExperience: {2}\nRole:"\
            " {3}\nRole Stats:\nHealth: {4}\nAttack: {5}\nDefense: {6}".format(self.name, self.level, self.totexp, self.role, self.health, self.attack, self.defense)
        )
def choose_name():
    while(True):
        Name = input("What is your Dicer's name?:\n").title()
        if(any(Bad_Words in Name.lower() for Bad_Words in [])):
            print("That's an inappropriate name! Try again")
        elif(len(Name) < 3):
            print("That name is too short! Try again.")
        elif(len(Name) > 16):
            print("That name is too long! Try again.")
        else:
            #you have to return the name so you can use it later
            return Name

def choose_role():
    #removed all the lambdas here
    Roles = {
   'mage': (100, 40, 10), #(Health, Attack, Defense)
   'warrior': (100, 30, 20),
   'gunner': (100, 20, 30),
   'archer': (100, 10, 40)
   }

    while(True):
        Role = input("What role do you want to be?\nChoices:\n1. Mage\n2. Warrior\n3. Gunner\n4. Archer\n").title()
        if(Role.lower() in (Roles)):
            #don't just return None, return the name of the role and it's 3-tuple stats
            #returning the role and it's stats from a function is not the best way to do this
            return Role, Roles[Role.lower()]
        else:
            print("That's not a role! Try again.")

dicer_name = choose_name()
dicer_role_name, dicer_role_stats = choose_role()

#create a dicer using the stats returned from chose_role() function
mainDicer = Dicer(dicer_name, dicer_role_name, dicer_role_stats[0], dicer_role_stats[1], dicer_role_stats[2])
mainDicer.print_info()

Here is how I would do it if writing it from scratch

class Dicer():
    def __init__(self, name, role, statTuple):
        self.name = name
        self.level = 1
        self.xp = 0
        self.health = statTuple[0]
        self.attack = statTuple[1]
        self.defense = statTuple[2]

    def print_stats(self):
        print("Name", self.name)
        print("Level", self.level)
        print("XP", self.xp)
        print("Health", self.health)
        print("Attack", self.attack)
        print("Defense", self.defense)


roles = {
    #health, attack defense
    "mage" : (100, 40, 10),
    "warrior" : (100, 30, 20),
    "gunner" : (100, 20, 30),
    "archer" : (100, 10, 40)
}
name = input("What is your name ")
dicer_role_choice = None
while dicer_role_choice not in roles.keys():
    print("Please select a dicer:")

    #prints each role on a new line, showing all the possible choices
    print("\n".join(roles.keys()))
    dicer_role_choice = input()

mainDicer = Dicer(name, dicer_role_choice, roles[dicer_role_choice])
mainDicer.print_stats()