Python not saving variable values when they are changed inside a function - python

I saved my variables at the start of my program and allow the functions to access them I believe but when they run the value is not saved when the function repeats.
P1_score = 0
P2_score = 0
round_number = 0
def dice_rolling():
# P1D1 means player ones dice one value and so on with P1D2
import random
# player ones turn
print("player ones turn")
P1D1 = random.randint(1, 6)
print("your number is ", P1D1)
P1D2 = random.randint(1, 6)
print("your second number is", P1D2)
# player twos turn
print("player twos turn")
P2D1 = random.randint(1, 6)
print("your number is", P2D1)
P2D2 = random.randint(1, 6)
print("your second number is", P2D2)
score_calculation(P1D1, P1D2, P2D1, P2D2,P1_score,P2_score,round_number)
def score_calculation(P1D1, P1D2, P2D1, P2D2,P1_score,P2_score,round_number):
import random
round_number = round_number + 1
# player 1 score calculation
total_P1 = P1D1 + P1D2
P1_score = P1_score + total_P1
if total_P1 % 2 == 0:
P1_score = P1_score + 10
else:
P1_score = P1_score + 5
if P1D1 == P1D2:
P1D3 = random.randint(1, 6)
P1_score = P1_score + P1D3
# player 2 score calculation
total_P2 = P2D1 + P2D2
P2_score = P2_score + total_P2
if total_P2 % 2 == 0:
P2_score = P2_score + 10
else:
P2_score = P2_score + 5
if P2D1 == P2D2:
P2D3 = random.randint(1, 6)
P2_score = P2_score + P2D3
print("player ones score at the end of round", round_number, "is", P1_score)
print("player twos score at the end of round",round_number,"is",P2_score)
for x in range(0,5):
dice_rolling()
Any help would be appreciated and if someone could give a simple explanation as to what I'm doing wrong and what to fix would be great.

Python can read from global variables inside a function, but can't assign them without some extra work. In general, when you want to use a global variable, it's a good idea to make it explicit by using the global keyword in your function:
my_global_var = 0
def some_function():
global my_gobal_var
my_global_var = 10
print(my_global_var) # it prints 10
somefunction() # modifies the global var
print(my_global_var) # now it prints 10

Variables are defined and used locally. Consider this example.
x = 1 #initial value
def test(x):
print(x) #print what you got
x += 1
print(x) #print updated value
print(x) #Actual printouts here
test(x)
print(x)
This results in :
1
1 #value when entering the function
2 #Value changed by function
1 #value outside the function did not change
If you want the variables to be maintained in functions, consider using class variables or global variables. (I recommend avoiding globals as you get to more complex problems)
Global example:
global x
x = 1
def test():
global x
x+=1
print(x)
test()
print(x)
test()
print(x)
Results in :
1
2
3
Finally class variables:
class test_class():
def __init__(self):
self.x = 1 #variables defined like this are class variables
def test(self):
self.x += 1 #Advantages of class variables is that you can defined them in the __init__ function
def running(self):
print(self.x) # And you can access it from multiple functions without using globals and much more too.
self.test()
print(self.x)
if __name__ == '__main__':
tclass = test_class()
tclass.running()

Related

Why is the varible always the same when using random(python) [duplicate]

This question already has answers here:
Using global variables in a function
(25 answers)
Closed last year.
So i am making a small game with damage and the terminal always gets printed "Nukupana does 0 damage" Any idea why this would be?
Here is the code:
Strength = 5
Magic = 5
Speed = 5
Lifeforce =5
base_health = Lifeforce *10 +50
damage_done=0
curent_health = base_health - damage_done
##functions for stuff
def glacius():
magic_damage = 5 * random.randint(1,5)
damage_done = magic_damage
def nukapana_moves():
moves = ["Glacius"]
attack = random.choice(moves)
if attack == "Glacius" :
glacius()
print(f"nukapana uses {attack} it does {damage_done}.")
In your glacius function, damage_done is a local variable. The damage_done in global namespace doesn't see the change unless you use the global keyword in the glacius function to tell Python damage_done should be global:
import random
Strength = 5
Magic = 5
Speed = 5
Lifeforce = 5
base_health = Lifeforce * 10 + 50
damage_done = 0
curent_health = base_health - damage_done
##functions for stuff
def glacius():
global damage_done # <---- here
magic_damage = 5 * random.randint(1, 5)
damage_done = magic_damage
def nukapana_moves():
moves = ["Glacius"]
attack = random.choice(moves)
if attack == "Glacius":
glacius()
print(f"nukapana uses {attack} it does {damage_done}.")
nukapana_moves()
note: Often depending on global variables considered a bad practice. Instead you should free your code from depending on a global variable by returning values from functions. Functions should do their jobs independently.
Re-implementation using class:
import random
class Hero:
def __init__(self):
self.strength = 5
self.magic = 5
self.speed = 5
self.lifeforce = 5
self.base_health = self.lifeforce * 10 + 50
self.damage_done = 0
#property
def current_health(self):
return self.base_health - self.damage_done
def glacius(self):
self.damage_done = 5 * random.randint(1, 5)
def nukapana_moves(self, moves):
attack = random.choice(moves)
if attack == "Glacius":
self.glacius()
print(f"nukapana uses {attack} it does {self.damage_done}.")
player = Hero()
print(player.current_health)
player.nukapana_moves(['Glacius'])
print(player.current_health)
output:
100
nukapana uses Glacius it does 25.
75
note: When you hit damage you need to re-calculate the current_health, Or as I've done here use a property that gives you the correct value. Otherwise you hit damage but the self.current_health doesn't change because it calculated once in the initializer.

"local variable referenced before assignment" but I think I need to?

I'm receiving "local variable 'var_1_mon' referenced before assignment" and "local variable 'var_0_mon' referenced before assignment" when entering 0 or 1 for racer = str(input(">")). But to my knowledge I've already assigned their values, and if I assigned them after def game() it will reset my variables to those values after every turn.
I've tried putting the initial variable values after "def game()" and removing the Game loss and Victory conditions, but then choosing var_0 ended the program and var_1 didn't loop back to game().
import random
import time
def start():
var_0_mon = 100
var_1_mon = 100
def game():
var_0 = 0
var_1 = 0
racer = str(input(">"))
if racer in ("0"):
player_mon = var_0_mon
enemy_mon = var_1_mon
elif racer in ("1"):
player_mon = var_1_mon
enemy_mon = var_0_mon
while var_0 <= 100 or var_1 <= 100:
var_0 = var_0 + random.randint(1,2)
var_1 = var_1 + random.randint(0,3)
print ("Var 0:", var_0, "Var 1:", var_1)
if var_0 >= 100 or var_1 >= 100:
break
if var_0 >= 100 and var_1 >= 100:
print ("Tie!")
elif var_0 >= 100:
var_0_mon = var_0_mon + 25
var_1_mon = var_1_mon - 25
print ("Var 0 Match Victory!")
elif var_1 >= 100:
var_0_mon = var_0_mon - 25
var_1_mon = var_1_mon + 25
print ("Var 1 Match Victory!")
game()
if player_mon <= 0:
print ("Game Loss")
elif enemy_mon <= 0:
print ("Game Victory!")
start()
I expected def start() to define the beginning of the game, so the player could choose a racer = str(input(">")) to choose between making their player_mon var_0_mon or var_1_mon. Then the game would proceed with var_0 or var_1 receiving random integers (1 - 2 and 0 - 3 respectively), upon which one would reach 100 before the other, or they would tie. Upon a tie, their the player_mon and enemy_mon would remain untouched, however upon the player winning, whichever of the two variable racers they've chosen (var_0 or var_1.) They would receive 25 to their player_mon and the enemy would lose 25 of their enemy_mon, and vice versa. game() would then return them to choose a racer, (var_0 or var_1). This would continue until one variable racer (var_0 or var_1) lost all of their money, if player_mon <= 0: or elif enemy_mon <= 0: printing "Game Loss" or "Game Victory" respectively, and then looping back to the very beginning of the program using start()
As soon as you assign to var_1_mon inside game, you create a new local variable that shadows the one defined inside start. You need to declare it non-local so that assignments affect start's variable rather than create a new one.
def start():
var_0_mon = 100
var_1_mon = 100
def game():
nonlocal var_0_mon, var_1_mon
...

Trying to fix TypeError: freqRolls() missing 1 required positional argument: 'sides' python

I am a new python programmer and I am creating a program that will randomly generate dice program that will choose how many sides of a dice it is going to use, so I can then, later on, figure out how to print the frequency of how many times the dice landed on that number. I am getting a "TypeError: freqRolls() missing 1 required positional argument: 'sides' error when trying to print out how many sides the dice has starting at 1 and going up to the number of sides the program decided to use.
import random
listRolls = []
#Randomly choose the number of sides of dice between 6 and 12
#Print out 'Will be using: x sides' variable = numSides
def main() :
global numSides
global numRolls
numSides = sides()
numRolls = rolls()
rollDice()
listPrint()
freqRolls()
def rolls() :
x = (random.randint(200, 500))
print('Ran for: %s rounds' %(x))
return x
def sides():
y = (random.randint(6, 12))
print('Will be using: %s sides' %(y))
return y
def freqRolls(sides):
for i in range(1, len(sides)) :
print("%2d: %4d" % (i, sides[i]))
# Face value of die based on each roll (numRolls = number of times die is
thrown).
# numSides = number of faces)
def rollDice():
i = 0
while (i < numRolls):
x = (random.randint(1, numSides))
listRolls.append(x)
# print (x)
i = i + 1
# print ('Done')
def listPrint():
for i, item in enumerate(listRolls):
if (i+1)%13 == 0:
print(item)
else:
print(item,end=', ')
main()
When you declared the freqrolls() function in this piece of code
def freqRolls(sides):
for i in range(1, len(sides)) :
print("%2d: %4d" % (i, sides[i]))
the "sides" is an argument, it means that the function expects a value and will call it "sides" only inside the function. To your function work, you need to pass this value in the moment you call it, like this:
freqRolls(numSides)

Python code repeats 8 times when not necessary

def Reset():
global seven_digit
seven_digit = ["","","","","","",""]
global x
x = 0
global eight
eight = 0
global c
c = 0
cinput()
def cinput():
global thing
print("Enter digit ", x+1)
thing = input("")
check()
def check():
global eight
global x
if not thing.isdigit():
print("That character is not allowed")
cinput()
elif len(thing) > 1:
print("Those characters are not allowed")
cinput()
if x < 7:
seven_digit[x] = int(thing)
x += 1
cinput()
if x == 7:
eight = int(thing)
fcheck()
def fcheck(): #this section is temporary just for testing
global c
c+=1
print("This is c, ", c)
print("Test")
print(seven_digit)
print(eight)
Reset()
This is the code I have been developing as an a-level task (it is this years GCSE course) however I have stumbled across a problem where the last section in the self-created function of fcheck() repeats itself 8 times. I have used a similar process before in python and I have never seen an error like it before. I was wondering if anyone knew what I could do to fix it, thanks.
There is a mutual calling between check and cinput, so, it you call fcheck inside this chain of calls, it will be called 8 times.
If you want to call fcheck once, after the all evaluation chain, you can just remove the call to it at the last line of check, and call it at the end of Reset:
def Reset():
global seven_digit
seven_digit = ["","","","","","",""]
global x
x = 0
global eight
eight = 0
global c
c = 0
cinput()
fcheck()
def cinput():
global thing
print("Enter digit ", x+1)
thing = str(input(""))
check()
def check():
global eight
global x
if not thing.isdigit():
print("That character is not allowed")
cinput()
elif len(thing) > 1:
print("Those characters are not allowed")
cinput()
if x < 7:
seven_digit[x] = int(thing)
x += 1
cinput()
if x == 7:
eight = int(thing)
def fcheck(): #this section is temporary just for testing
global c
c+=1
print("This is c, ", c)
print("Test")
print(seven_digit)
print(eight)
Reset()

How do I get rid of local variable referenced before assignment error?

I'm trying to make a simple program that generates a board on which you move around as X.
Code:
from msvcrt import getch
import os
board = []
for x in range(20):
board.append(["O"] * 20)
def print_board(board):
for row in board:
print " ".join(row)
def keys(coordx, coordy):
global coordY
global coordX
key = ord(getch())
if key == 97:
coordx -= 1
elif key == 100:
coordx += 1
elif key == 115:
coordy -= 1
elif key == 119:
coordy += 1
def play(coordx, coordy):
global coordY
global coordX
while True:
board[coordx][coordy] = "X"
print_board(board)
keys(coordx, coordy)
os.system('cls')
coordX = 10
coordY = 10
play(coordX, coordY)
Every time i want the program to change the value of coordX or coordY i get UnboundLocalError: local variable coordY/coordX refferenced before assignment. I tried different methods - making variables global, making arguments for functions instead of using the variables while defining functions and nothing worked.
Once you call play, you never make any assignments to either coordX or coordY, which would explain why they never change.

Categories

Resources