user3092741
user3092741

Reputation: 69

UnboundLocalError: local variable 'strength' reference before assignment

I have got a program which determines the outcome of two characters. There is an error, and I do not know how to fix it. I have tried create the variables global, but it doesn't work.

code:

import random, sys

y_n = ["yes", "Yes", "y", "ye", "yeah", "Ye", "Yeah", "Y"] # list of all possible inputs for Yes.
r = random.randrange # this is to make getting a random number shorter.

class Character(): # class. holds attributes, and methods.
    name = "" #name of the character
    random_attr = "" # do you want the attributes to be randomly generated or inputted manually?
    strength, skill = 0,0 #strength and skill attributes
    dice = 0 # dice score


    def charInputs(self, random_attr): #method
        #holds prompts for input
        prompts = ("Enter Strength Attribute, between 1 and 50: ", "Enter Skill Attribute, between 1 and 50: ") 


        if random_attr in y_n: # if the user has said anything in the y_n list,
            strength, skill = r(1,50), r(1,50) #create random attributes
            #prints out your name, and your attributes
            print(self.name + " - STRENGTH = ", strength, " SKILL = ", skill)
        else: # if no
            try: # 'try' is used for error handling
                answers = [int(input(p)) for p in prompts] 
                # this is a list comprehension. it loops through the prompts and gets inputs from them

                if not all(0 < a <=50 for a in answers): # generator expression - loops through the answers list
                    # and if it is above 50 or below 0, it returns false. else it returns true (because of the
                    # all() function).
                    print("You did not enter an attribute(s) between 1 and 50. Program closing.")
                    #exit here
                else: # if the above expression returns True
                    strength, skill = answers #gets the attributes from the answer lists
                    print(self.name + " - STRENGTH = ", strength, ", SKILL = ", skill) #prints them out

            except ValueError: # if user has not entered a integer
                print("Program exiting. You did not enter a valid data type.") #prints
                #exit here


        return strength, skill; #returns attributes so they can be used outside the function and placed
        # into variables


    def Mods(self, oth_chr, strength, skill, name): # method for creating the modifiers.
        #(you, other character, strength, skill, your name) <---- this is what is inside those brackets
        if c1.strength > oth_chr.strength: # if your strength is greater than the enemies
            str_diff = c1.strength - oth_chr.strength #create strength differences
        elif c1.strength == oth_chr.strength: # if they are both the same
            print("no outcome. both strengths were the same. No modifier could be created.")
            quit()
        else: # if enemies character is greater than yours
            str_diff = oth_chr.strength - c1.strength

        if c1.skill > oth_chr.skill: # if your skill is greater than the enemies
            ski_diff = c1.skill - oth_chr.skill #create skill difference
        elif c1.skill == oth_chr.strength: # if they are the same
            print("No outcome. Both skills were the same, no modifier could be created.")
            quit()
        else: # if the enemies is greater than yours
            ski_diff = oth_chr.skill - c1.skill

        str_mod = str_diff // 5 # creates strength and skill modifiers
        ski_mod = ski_diff // 5

        return str_mod, ski_mod; #returns them so they can be used outside the method and be put into variables

    def diceRollAndOutcome(self, ch2, strength, skill, str_mod, ski_mod, name): # method that is for determining
        # the dice roll and outcome
        c1.dice, ch2.dice = r(1,6), r(1,6) # rolls the dice

        if c1.dice == ch2.dice: # if the dice are the same
            print("No outcome. Both sides are the same.") # no outcome
            #exit here
        elif c1.dice > c2.dice: # if character 1's is greater
            c1.strength += str_mod # adds strength modifier
            c1.skill += ski_mod # adds skill modifier 

            print(self.name + "'s dice is greater than " + ch2.name +  "'s dice!\n")
            ch2.strength -= str_mod # subtract strength mod from character 2 strength
            print("STRENGTH MODIFIER = ", str_mod, " has been subtracted from " + ch2.name + "'s strength attribute. It's strength is now ", ch2.strength, "\n") # prints 
            ch2.skill -= ski_mod # subtract skill modifier from character 2 skill
            print("SKILL MODIFIER = ", ski_mod, " has been subtracted from " + ch2.name + "'s skill attribute. It's skill is now ", ch2.skill, "\n") # prints

            if ch2.strength <= 0: # is character 2's strength less than or = to 0?
                ch2.strength = 0 # make character 2 strength 0
            else: # if not
                print(ch2.name + " has not died! It's remaining strength is ", ch2.strength) # print character 2 has some strength remaining

            if ch2.skill <= 0: # if c2's skill is less than or = to 0
                print(ch2.name + "'s skill has ran out!\n") # skill has ran out
            else:
                print(ch2.name + " has some skill left! It's remaining skill is ", ch2.skill) # print c2 has some skill remaining
        else: # if character 2's dice is greater than c1's
            print(ch2.name + "'s dice is greater than " + name + "'s dice! \n")
            self.strength -= str_mod # strength mod is subtracted from character 1's strength
            print("STRENGTH MODIFIER = ", str_mod, " has been subtracted from " + self.name + "'s strength attribute. It's strength is now ", self.strength, "\n")
            self.skill -= ski_mod # skill mod is subtracted from character 1's skill 
            print("SKILL MODIFIER = ", ski_mod, " has been subtracted from " + self.name + "'s skill attribute. It's skill is now ", self.skill, "\n")

            if self.strength <= 0: # if c1's strength is less than or = to 0
                self.strength = 0 # c1's strength is 0
            else: # if not
                print(self.name + " has not died! It's remaining strength is ", self.strength) # c1 has not died

            if self.skill <= 0: # if c1's skill is less than or = to 0
                print(self.name + "'s skill has ran out!\n") # c1's skill has ran out
            else:
                print(self.name + " has some skill left! It's remaining skill is ", self.skill) # c1's skill has not ran out


c1 = Character() # creates instance of Character class inside "c1"
c2 = Character() # creates instance of Character class inside "c2"
c1.name = str(input("PLAYER 1 - Enter your characters name: ")) # input character name
c2.name = str(input("PLAYER 2 - Enter your characters name: ")) # input character name

c1.random_attr = str(input("PLAYER 1 - Would you like your attributes to be randomly generated? Yes or No: ").lower()) # would the character like their attributes randomly generated or not
c1.strength, c1.skill = c1.charInputs(c1.random_attr) # returned strength and skill attributes are put into variables

c2.random_attr = str(input("PLAYER 2 - Would you like your attributes to be randomly generated? Yes or No: ").lower()) # would the character like their attributes randomly generated or not
c2.strength, c2.skill = c2.charInputs(c2.random_attr) # returned strength and skill attributes are put into variables

str_mod, ski_mod = c1.Mods(c2, c1.strength, c1.skill, c1.name) # returned strength and skill modifiers are put into variables

c1.diceRollAndOutcome(c2,c1.strength, c1.skill, str_mod, ski_mod, c1.name) # calls diceRollAndOutcome method

Error:

Traceback (most recent call last):
  File "N:\CA\task 3\task 3.py", line 118, in <module>
    c1.strength, c1.skill = c1.charInputs(c1.random_attr) # returned strength and skill attributes are put into variables
  File "N:\CA\task 3\task 3.py", line 41, in charInputs
    return strength, skill; #returns attributes so they can be used outside the function and placed
UnboundLocalError: local variable 'strength' referenced before assignment

How can I fix this? What is wrong with it - and how can I prevent doing this in the future?

The error points to line 118 and 41, I have looked through other questions but they don't make sense, as it is not my code they are working on.

Upvotes: 0

Views: 380

Answers (3)

Germano
Germano

Reputation: 2482

In your charInputs function there is a flow path that does not assign any value to strength nor skill.

The class variables that you define in your class are not visible inside your function, unless you use self.strength and self.skill inside charInputs.

But, looking closer at your class, I'd rather define some defaults inside an __init__ function.

Upvotes: 2

Martijn Pieters
Martijn Pieters

Reputation: 1121386

In your charInputs function there is a path where you can end up without strength and skill being assigned to.

If random_attr in y_n is False, the else branch is taken. In that branch you only assign no strength and skill if answers = [int(input(p)) for p in prompts] does not throw an exception and all(0 < a <=50 for a in answers) is True. If neither of these are true (so the user enters a string, or a value outside the valid range), you end up at the end of the function with no assignments for these two names.

Your code has comments for those cases stating you need to exit, but you don't actually do so.

Upvotes: 1

Mihai Zamfir
Mihai Zamfir

Reputation: 2166

Your second else and your return statements in the charInputs function don't know who strength is. This variable does not exist inside the scope of charInputs function

Upvotes: 0

Related Questions