Variable refrenced before assignment Python - python

I went through this a couple of times and couldnt fine anything wrong so its probably something over my head. I also apology for what is going to be an assault on your eyes, its my first year of programming and have probably made multiple etiquette errors.
print('Befor we begin, when you are given options, I ask you to type your input as show, failure to do so will break the program and you will lose all of your progress')
def test():
print('it has worked!')
def stats():
global attack
global health
global mashealth
global agility
if race in ('human','Human'):
maxatk=4
maxagi=4
attack = lambda:random.randint(2,maxatk)
maxhealth = 20
health=20
agility = random.randint(maxagi,10)
elif race in ('Orc','orc'):
attack = random.randint(3,maxATK)
maxhealth = 25
agility = random.radint(maxAGI,10)
def main():
while True:
print('What would you like to do')
print('Rest Shop Fight')
answer=input('-')
if answer in ('Rest','rest'):
health=maxhealth
continue
def character():
global race
global name
global gender
print('What would you like the name of your character to be?')
name=input('-')
print()
print('What race will your character be?')
print('Human Orc Elf')
while True:
race = input('-')
if race in ('human','Human','Orc','orc','Elf','elf'):
break
else:
print('Not a valid response, try again')
continue
print()
print('What gender is your character')
gender=input('-')
print()
def goblin():
goblinatk=1
goblinhealth=100
while True:
print('You have encountered a goblin, what will you do?')
do=input('-')
if do == 'attack':
damage=attack()
goblinhealth=goblinhealth-damage
print('You did',damage,'damage to the goblin')
print('The goblin has',goblinhealth,'hp')
goblinatk=lambda:random.randint(3,10)
health=health-goblinatk
print('the goblin did',goblinatk,'to you')
print('you have',health,'hp')
if goblinhealth <0:
print('The goblin has died')
break
if health <0:
print('you have died')
break
character()
stats()
goblin()
test()
The error is here
Traceback (most recent call last):
File "H:\16CoFrega\Code\Python\GAME.py", line 255, in <module>
goblin()
File "H:\16CoFrega\Code\Python\GAME.py", line 238, in goblin
health=health-goblinatk
UnboundLocalError: local variable 'health' referenced before assignment

You need to specify the health as a global variable, otherwise it would be considered as a local variable, since you assign to it inside the function. Example -
def goblin():
global health
goblinatk=1
goblinhealth=100

def goblin():
............
health=health-goblinatk
............
Look at this function definition. Your function doesn't know what health is, so it won't allow you to subscript something from health.
So, somehow function has to recognize what is health. Two most common way:
First way, Declare health as a global variable. Now health can be recognized globally. But this is not the best way, as dealing with global variables are hard and error-prone and you are already handling too many global variables. So, i won't recommend it. I would rather suggest you to replace all the global variables with method 2. To understand why I am telling this, Read This Question
Second way, the recommended way, is to pass the health variable as the parameter of the function and at the end, return it from the function.
Like this:
def goblin(health):
............
health=health-goblinatk
............
return health
If you are already returning something, don't worry. With python, you can return more than one variable as a tuple.
return statement:
return a,b,c
calling statement:
a,b,c = func()
Hope this helps :)

Related

Why can't you name an object, which is created in a function, exactly the same as it's class-name in Python?

I'm programing a Black Jack game in a Jupyter notebook and for that I have a "player" and a "dealer" class and also a function (BlackJack()) which basically runs the entire game.
def BlackJack():
name = input("What is your name: ")
while True:
try:
money = int(input(f"Welcome to our casino Black Jack game {name}!How big is your balance in € : "))
except ValueError:
print("Just give me a number: ")
else:
print("Ok, let's start!")
break
player = player(name, money) # player() class
dealer = dealer() # dealer() class
An error occurs when I try to create class-objects with the same name as the class itself:
Error message:
What is your name: "Richard"
Welcome to our casino Black Jack game "Richard"!How big is your balance in € : 19163
Ok, let's start!
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-55-3c92f609e237> in <module>
----> 1 BlackJack()
<ipython-input-54-57fc63786581> in BlackJack()
9 print("Ok, let's start!")
10 break
---> 11 player = player(name, money)
12 dealer = dealer()
UnboundLocalError: local variable 'player' referenced before assignment
But if I name the class-objects different or I name them the same, but outside a function there is no error:
def BlackJack():
name = input("What is your name: ")
while True:
try:
money = int(input(f"Welcome to our casino Black Jack game {name}!How big is your balance in € : "))
except ValueError:
print("Just give me a number: ")
else:
print("Ok, Let's Start!")
break
plyr = player(name, money)
dlr = dealer()
or
player = player("Jimmy", 1200)
Is it just because in a function Python thinks that I want to assign a variable to itself before I've even assigned the variable (dealer = dealer()), even if they are not actually the same, because one is a variable and the other is a class? So does Python in this case just ignore the fact that e.g. dealer() is a class instead of the variable "dealer"?
Thanks in advance!
P.S.: I use Python 3.7.4
Assigning to a name anywhere in a function makes it a local variable, unless the variable has been declared global in the function. Attempting to refer to this variable before you've given it a value is an error.
So looking at your code:
player = player(name, money)
The name player is a local variable, and does not yet have a value. But you are attempting to call it like a function or class. You can't do that.
If you use a different name on the left side, as you discovered, player refers to the class you defined and it works.
This is (one reason) it is standard Python style to use capitalized class names. This will solve the problem and make it clearer that you are instantiating a class.
player = Player(name, money)
Similarly, because BlackJack is a function, it should be named blackjack.

Changing a local variable in multiple functions in Python?

background: I'm currently writing a text-based adventure and each enemy has a certain amount of turns you can attack it before it attacks back.
So to handle this the code sets an argument in the function for the fight dictating how many times you can attack.
def fight_sequence(rounds):
while rounds > 0:
attack = input()
if attack == magic:
magic("you teleport away to safety. Congratulations you have stayed alive through your journey and found a few souvenoirs. nice job!", 1, "you muster up all of your energy, chant the spell.... and nothing happens.Cthulu... seems unimpressed", 1, "")
elif attack == sword:
sword(1)
def magic(teleportmessage, teleportsuccess, firemessage, firefail, winmessage):
x = 0
while x == 0:
fightorflight = input("""you open the book to cast a spell
Do you want to try teleporting or use a fireball?""").lower()
if "teleport" in fightorflight:
if teleportsuccess = 1:
print(teleportmessage)
x = 1
else:
choice = input("You can't teleport out of this battle. Would you like to try a fireball?")
if choice == yes:
fightorflight = "fireball"
else:
x = 1
elif "fire" in fightorflight:
print(firemessage)
if firefail == 1:
choice = input("do you want to try to teleport instead?").lower()
if "yes" in choice:
fightorflight = "teleport"
else:
x = 1
else:
print(winmessage)
else:
print("Sorry not sure what you mean")
def sword(attacksuccess):
if attacksuccess == 1:
print("You pull out the sword and swing at the monster damaging it severely.")
else:
print("You pull out the sword and swing at the monster, but its immune to blunt objects.")
fight_sequence(3)
both magic() and sword() need to be able to decrease rounds by 1, originally i just did that before entering the magic or sword function. however some items to attack with allow you to attack more than once if you want so that won't work for them. Such as magic if they also choose to teleport. Is there a way to allow me to change the variable rounds while inside of another function?
I think using a return value might help but I'm not sure how to go about it
You can simply add a new argument to the magic function, and pass the 'rounds' variable through when you call it.
e.g.
def fight_sequence(rounds):
...
magic("some message", false, "fired", false, "you won", rounds)
def magic(teleportmessage, teleportsuccess, firemessage, firefail, winmessage, rounds):
Your passing through the variable (not just the value) so it will change in every context where rounds can be seen.
HTH.
I would recommend using classes to create this game rather than lots of functions, an example of a class in a hero game below.
class Hero:
def __init__(self):
self.health = 10
def eatApple(self):
self.health += 1
def takeDamage(self):
self.health -= 1
init function runs as class is initialized.
player = Hero()
print(player.health) # will print 10
player.takeDamage()
print(player.health) # will print 9
This way you can have global variables for you functions which can be changed in each function and is much more organised.

Using Python Class to make game- how to update self init?

I am making a text-based game on python using the class system to keep track of main character changes (like its name). I am writing the main code for the game outside of the Main Character Class- inside of the main function.
I am struggling because I need to update self.character_name inside the Main Character class to an input from the user inside the main function. I am unsure how to do this, I have the code written below- however it is not updating the name inside Main Character class. How can I rewrite this?
I'm also worried that I will have this problem when trying to update pets, characters_known. However, I do not seem to have this problem with updating Health or XP....
class Main_Character():
def __init__(self):
self.health=100
self.exp=0
self.level=0
self.character_name=""
self.characters_known={None}
self.pets={None}
self.progression_tracker=0
def __str__(self):
return "Name: "+ str(self.character_name)+" | "+ "Health:"+ str(self.health) + " | " +"XP:"+ str(self.exp) + " | "+ "Level:"+ str(self.level)+" | "+"Pets:"+str(self.pets)
def Char_Name(self,name):
if name.isalpha()==False:
print("You entered a name containing non-alphabetic characters, pease reenter a new name:")
main()
elif len(name)>=10:
print("You entered a name containing 10 or more characters, pease reenter a new name:")
main()
else:
self.character_name=name
def Char_Level_Experience(self,exp,b):
self.exp+=exp
b=2
if exp<=0:
exp=1
ans = 1
level=0
while ans<exp:
ans *= b
level += 1
if ans == exp:
self.level=level
print("You have reached level", self.level)
else:
level = int(log(exp, 2))
level = min(level, exp)
if level>=0:
self.level=level
else:
level=0
def healing(self,heal):
if self.health+heal>=100:
self.health=100
else:
self.health+=heal
def other_answers(answer):
if answer=='quit':
raise SystemExit
if answer=='pets':
print("Pets owned:", Main_Character().pets)
user_decision=input("Would you like to continue where you left off? Type 'yes' to continue, or 'no' to go back to main menu")
if user_decision=='yes':
if Main_Character().progression_tracker==0:
main()
elif Main_Character().progression_tracker==1:
choice1()
if user_decision=='no':
main()
else:
other_answers(user_decision)
if answer=='characters':
print("Characters met:", Main_Character().characters_known)
user_decision=input("Would you like to continue where you left off? Type 'yes' to continue, or 'no' to go back to main menu:")
if user_decision=='yes':
if Main_Character().progression_tracker==0:
main()
if Main_Character().progression_tracker==1:
choice1()
if user_decision=='no':
main()
else:
other_answers(user_decision)
def start_check():
print("If you understand the game, type 'go' to continue- if not, type 'more information' to receive more information about how to play the game")
begin_game=input("")
if begin_game=="go":
choice1()
if begin_game=='more information':
print("\n","The object of the game is to gain XP [experience points] without dying")
start_check()
else:
other_answers(begin_game)
def choice1():
Main_Character().progression_tracker=1
print("You are a knight in the Kings Guard- the King has asked to meet with you about a very special mission")
print("What would you like to do?")
print(" 1.Go Directly to King","\n", "2. Finish your dinner")
choice=input("1 or 2?")
if choice=="1":
Main_Character().Char_Level_Experience(1,2)
elif choice=="2":
Main_Character().Char_Level_Experience(.5,2)
else:
other_answers(choice)
print(Main_Character())
def main():
print("Welcome!")
unfiltered_name=input("Please enter the name of your character:")
Main_Character().Char_Name(unfiltered_name)
print("Welcome,", Main_Character().character_name,"!", "Here are your current stats!")
print(Main_Character())
start_check()
You haven't quite understood how classes and instances work.
Calling the class is what you do when you need a new character. Every time you call Main_Character(), you get a whole new instance - with the default values as set in __init__. If you had characters for each of your friends, you would call it one time for each one. You then would need to keep each of those instances in a variable, so you can reference them again each time.
So, for instance:
my_character = Main_Character()
unfiltered_name=input("Please enter the name of your character:")
my_character.Char_Name(unfiltered_name)
print("Welcome,", my_character.character_name,"!", "Here are your current stats!")
print(my_character)
You create a new character each time you call Main_Character. Instead, you should call it once:
the_character = Main_Character()
...
the_character.name = "..."

How to call a variable inside a function then use it in another function

im doing a little project for myself to understand the function, if statement in python. i want to call the "name" inside the user function and use it in jungle function.
def user():
global name
name = raw_input("Whats your name?")
def jungle():
print name, "Please, Select your Enemy"
print '\n'.join(jungle_enemy)
enemy = raw_input('> ')
if enemy == "1":
print "The Lion Will eat you alive."
game_over()
exit_countdown()
elif enemy == "2":
print "The Jaguar will tear you apart."
game_over()
exit_countdown()
elif enemy == "3":
print "The Snake will eat you whole."
game_over()
exit_countdown()
else:
try_again("Are You Noob? \nNone of the Choice!")
jungle()
when i run this code. it gives me an error.
NameError : global name 'name' is not define.
Global variables are a bad idea in general. Better pass the variable to whoever needs it:
def user():
return raw_input("Whats your name?")
def jungle(name):
print name, "Please, Select your Enemy"
# etc.
and then call the functions like this
username = user()
jungle(username)
If you have to use global names, you need to use the global statement in all the functions that use that variable - so you need to add global name at the start of jungle(). But don't do that. See where global variables have taken JavaScript - you don't want to do that in Python.

Python: Returning a list doesn't work

I am trying to make a program that can add/delete/show students in a class, and the 5 classes are 5 lists in a list.
Help is greatly appreciated.
When I run this code:
global classes
def intro():
print("Welcome to Powerschool v2.0!")
print("Actions:")
print("1. Add Student")
print("2. Delete Student")
print("3. Show Students in a Class")
print("4. Show All Students")
x = int(input())
while x<1 or x>4:
print ("Please choose an action, 1-4.")
x = int(input())
if x == 1:
action1()
elif x == 2:
action2()
elif x == 3:
action3()
elif x == 4:
action4()
classes = [[],[],[],[],[]]
return classes
def action1():
print("Which Class? 1-5")
a = int(input())
print("Please enter the student's name.")
z = input()
classes[a-1].append(z)
again()
def action2():
print ("Which Class? 1-5")
print ("Which student?")
again()
def action3():
print ("Which Class? 1-5")
y = int(input())
if y == 1:
print (classes[0])
elif y == 2:
print (classes[1])
elif y == 3:
print (classes[2])
elif y == 4:
print (classes[3])
elif y == 5:
print (classes[4])
again()
def action4():
print (classes)
again()
def again():
print("Would you like to do something else? y/n")
h = input()
if h == "y":
intro()
else:
quit
def main():
intro()
main()
My error is:
Traceback (most recent call last):
File "C:\Documents and Settings\user1\My Documents\Downloads\az_studenttracker.py", line 67, in <module>
main()
File "C:\Documents and Settings\user1\My Documents\Downloads\az_studenttracker.py", line 65, in main
intro()
File "C:\Documents and Settings\user1\My Documents\Downloads\az_studenttracker.py", line 19, in intro
action1()
File "C:\Documents and Settings\user1\My Documents\Downloads\az_studenttracker.py", line 33, in action1
classes[a-1].append(z)
NameError: name 'classes' is not defined
I did return classes at the end of intro() but I see that doesn't work.
I followed some suggestions, and nothing really happened :/
You're defining classes in your intro method, and, even though it's returning it, your action1 method doesn't see any variable named classes anywhere.
Relevant answer on Python scope and relevant documentation.
return doesn't do what you think it does. return statements are a way of passing execution control back up a context (For example, from intro() to main()), with the ability to send back some information for the higher context to use. Although you're passing classes back to main(), you never do anything with it at that context so it goes away.
One way to solve the problem would be to declare classes as a global variable. This is the easiest thing to do, but isn't generally good design. You could do this either by using the global keyword before declaring the local variable classes in intro() (See this question for guidance on global), or by declaring classes outside any of your functions.
Another solution would be to pass classes as a parameter to your action functions.
In either case, you would need to declare classes before any calls to your action functions.
This is because classes is out of scope for the second two methods. Therefore, you have two options:
Option 1
Pass classes to the methods action1(), action2(), etc like so:
def action1(classes)
...and the when you call it:
action1(classes) //with the classes var you just made
Option 2 (recommended)
Simply put the classes var outside your methods or declare it global like so:
global classes = [[],[],[],[],[]]
...right before:
def intro()
In general, you should read up on how return works; it is not necessary in the code you wrote
classes only exists in intro():, you would have to declare it as a global variable to access it in other functions or declare it outside the function.
classes = [[],[],[],[],[]] # can be accessed by action3() ,action4()
def intro():

Categories