Python - Updating Variable in For Loop [duplicate] - python

This question already has answers here:
Using global variables in a function
(25 answers)
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Closed last month.
So I decided to write Monopoly in Python, but I'm having some trouble updating the players location. I wrote a for loop that iterates through the players, rolls the dice for each one, and then updates their location. The problem is that the location variable isn't keeping the latest location, it keeps resetting back to 0 at the start of the for loop. Here's my code:
player1location = 0
def turn(numberPlayers, player, player1location, Board):
for player in range(numberPlayers):
player = 'Player'+str(player+1)
print 'It\'s', player, 'turn!'
print player1location
rollDice = raw_input('Press Enter to roll the dice!')
diceRoll = random.randint(1,6)
print player, 'rolled a', diceRoll
player1location = player1location + diceRoll
print 'You landed on', player1location
print '\n'
while True:
turn(numberPlayers, player, player1location, Board)
I can provide more of the code if necessary, but I think this is everything that controls the players location. Thanks!
EDIT: So apparently I'm changing the local variable instead of the global variable. How would I change the global variable instead?

You have function parameter with the same name as your target variable which you want to update.
Due to which, any changes you make is made to the function parameter, and not to the global variable. That's because the function creates a local scope for the paremeter you are passing to the function. So, it overshadows the variable defined with the same name globally.
So, either change the name of the function parameter player1location or the name of the global variable.

Note that you have two variables called player1location - one is defined globally in your first line (outside of any function): player1location = 0, and the second one is created locally each time you call your function: def turn(numberPlayers, player, player1location, Board). Even though they have the same name, these are two distinct variables in python, because they are defined in different scopes.
There are a couple of ways you could fix this.
You could remove player1location from your function definition, and then you'd always be changing the globally-scoped variable. However, from your naming convention, I'm guessing that you'd like to reuse the function for other players as well (although it still couldn't hurt to try it, to help you understand how it works).
The better way would likely be to return the new player location at the end of your function (return player1location), and then assign it to the globally-scoped location upon return (player1location = turn(numberPlayers, player, player1location, Board)).

Related

Shadowing parameter in Python functions

I've got myself a bit confused regarding variables in Python, just looking for a bit of clarification.
In the following code, I will pass a global variable into my own Python function which simply takes the value and multiplies it by 2. Very simple. It does not return the variable after. The output from the print function at the end prints 10500 rather than 21000, indicating that the local variable created within the function did not actually edit the global variable that was passed to, but rather used the value as its argument.
balance = 10500
def test(balance):
balance = balance * 2
test(balance)
print(balance)
However, in my second piece of code here, when I pass a list/array into a separate function for bubble sorting, it is the actual array that is edited, rather than the function just using the values.
def bubble_sort(scores):
swapped = True
while swapped:
swapped = False
for i in range(0, len(scores)-1):
if scores[i] > scores[i+1]:
temp = scores[i]
scores[i] = scores[i+1]
scores[i+1] = temp
swapped = True
scores = [60, 50, 60, 58, 54, 54]
bubble_sort(scores)
print(scores)
Now when I print my scores list, it has been sorted. I am confused as to why the top function did not change the global variable that was passed to it, while the second function did? I understand using the global keyword within functions means I am still able to write code that will edit a global variable within my own functions, but maybe I am missing some basic understanding.
I think your confusion is about mutability.
Ints are immutable. When you assign balance initially, because it is an int, the value of balance won't change unless you reassign it. You know this, because you reassign it in your definition. However, the confusion in your situation is because there are actually two "balance" variables. The global one, and the one that exists inside your function each time you call. The assignment that happens within your function does not actually affect the assignment of the global variable. It doubly isn't really doing anything because there's no return value.
To actually change things, you would want
def test(balance):
balance = balance * 2
return balance
balance = test(balance)
The list situation is different because lists are actually mutable. This makes it so that when you're changing values in scores, you're really changing values in scores. And so when you call your function on it, it changes things without the need for reassignment.
This is generally a situation of remembering the inherent properties of the data types in python. Certain things are mutable and certain things are not. You can probably google up a quick chart, and the more you work in python, remembering the differences becomes second nature.
In both functions, the global variable is shadowed by the local variable.
In the test function, the global and local variables start by pointing to the same value, but the local variable is reassigned to another value.
In the bubble_sort function, the global and local variables also start by pointing to the same value. This time, instead of reassigning the local variable to a new value, you mutate the object it is pointing to. If in the bubble_sort function you reassigned the local variable, you would end up with a similar outcome to your test function.

Python 3 changing variable inside function without using global variables

So i am currently working on a university project, therefore i can't really paste my code to be more specific, but we have this stupid rule that global variables are not allowed and using them would lead to points removal. So my question is:
I am making a roll the dice game, where a couple of players take turns and i need a variable that identifies which player is on turn. I have a function, which represents each turn and a second, which calls the first function multiple times, which is equal to the number of players. Lets say i have 3 players:
def func1():
player_on_turn = 1
result = 0
print('Player',player_on_turn,'is on turn.')
#something
return result
def func2():
players = 3
for player in range(1,players+1):
player = func1()
func2()
So this variable player_on_turn has to change 3 times, meaning for each call of the function. The first call it is equal to 1, the second to 2, etc.
I've done this already with global variable, but apparently i can't use them, because "it makes the code hard to read". In the first function i am already using return for a one value which changes inside the function and is being reset each call. Is there a way i could probably do this? Thanks in advance!
You can use Function Parameters to pass data between functions.
You can also use a Class to create objects that store data without global variables.

NameError when using a variable returned by a function

I want to return the variable aRoll, and use it as the argument for the next function. In this case, aRoll holds the answer to the question "Let's roll your ability scores. ready? (y/n)" Once the question is answered, it raw input is stored in the variable aRoll and returned.
import random
pAbility = ['Str', 'Dex', 'Con', 'Int', 'Wis', 'Cha']
pScore = []
i = 0
def pQuestion():
aRoll = raw_input("Let's roll your ability scores. ready? (y/n)")
if aRoll not in ('y', 'n'):
print "Please type 'y' or 'n'"
return pQuestion()
else:
return aRoll
def pStats(aRoll):
while aRoll == "y":
while i < 6:
pScore.append(random.randint(7, 18))
i = i + 1
for score, ability in zip(pAbility, pScore):
print str(score) + ":\t\t " + str(ability)
def pReroll():
aRoll = raw_input("Do you wish to reroll? (y/n)")
aRoll = aRoll.lower()
if aRoll not in ('y', 'n'):
print "Please type 'y' or 'n'"
return pReroll()
pQuestion()
pStats()
pReroll()
When putting print aRoll after pQuestion(), at the bottom of the script, it tells me aRoll isn't defined. Am I not returning aRoll correctly?
aRoll as defined is a separate local variable in each function. You either need to declare it as a global (not a good idea), or explicitly pass the return value of one function as an argument to the next. For example,
rv = pQuestion()
rv2 = pStats(rv)
rv3 = pReroll(rv2)
(Note the change in the definition of pReroll this requires.)
A couple of the other answers have it partly right, but you have to put their answers together to get what you want. At the bottom, it should look like this:
aRoll = pQuestion()
pStats(aRoll)
First, you're assigning what pQuestion() returns to aRoll. Next, you're passing that in as a parameter to pStats(). There are a couple things that will happen if you don't do this:
Since you defined a parameter for pstats(), the interpreter will tell you that you're missing a parameter when you try to run this.
Due to the local scope of aRoll, that variable is not defined outside of the function pQuestion().
For more information about variable scope, look here. This page may also prove useful:
http://gettingstartedwithpython.blogspot.com/2012/05/variable-scope.html
pQuestion() returns aRoll but you never assign the return value. pStats() expects you to pass in aRoll but you never do.
You don't return "the variable" but the value of the variable at the point of the return statement. The name of the variable in the function is completely irrelevant. This is a Good Thing: functions are a way to encapsulate pieces of code. Imagine a simple function that adds two numbers:
def add(a, b):
result = a+b
return result
and then the author changes his mind and renames the variable inside the function:
def add(a, b):
sum = a+b
return sum
and finally, he's clever and just does
def add(a, b):
return a+b
As a user of this function, you should not bother about the names inside the function. You use the add function because you expect it to return the sum of the arguments, no matter how the function works internally.
If you want to use the result of a function, you must store it in a variable yourself:
sum_of_2_and_3 = add(2,3)
print(sum_of_2_and_3)
Not to be discouraging, but your code is a long way from working even once we correct the issue with aRoll. You'll probably have to follow up with some other questions.
As for your immediate problem:
aRoll is defined in pQuestion() and only exists for the duration of that function call (it is in scope only within that function).
When you return aRoll in the function the name aRoll is lost and the value of aRoll "pops out" of the function into the calling code. Unfortunately, you're not catching that value so it basically dissolves into the ether, never to be seen again.
In order to catch the value you need to assign it, like this:
answer = pQuestion()
Now, you have a new variable called answer containing the value "popped out" of the function pQuestion() (y or n in this case). Note that you could also write aRoll = pQuestion() and you'd have a variable named aRoll containing the value from pQuestion() but, importantly, it would not be the same variable as the one INSIDE pQuestion() because that one was already lost. While you're learning, it's probably a better idea to use different variable names everywhere so you don't get confused and believe that the same-named variables are actually the same (rather than variables in different scopes that coincidentally share a name)
That's thing one. Next, you have somehow get the value of answer or aRoll or foobar or whatever name you gave to that value into pStats(). You've already told pStats() to expect to receive one value and to name that value aRoll -- but this aRoll, like the first one, is in scope only inside the pStats() function. The problem is, you're not actually supplying the value to pStats(), which you would do like this:
pStats(answer)
or
pStats(aRoll)
or
pStats(foobar)
or whatever name you chose for the variable.
There is another solution to this problem which is to declare the variables as global and not pass them around. I urge you not to pursue this solution as it leads to very bad programming habits and should only be used in rare circumstances after you fully understand the idea of local scope.

Function Not getting called [duplicate]

This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Closed 6 months ago.
I have function which checks the score and will(I haven't finished) increases level if the score hits the given score, my function:
def levels(Score):
if score >= 100:
enemies = 6
velocity = 2
and I'm calling it in the game loop:
levels(score)
The function never gets executed, my source code http://pastebin.com/JPZSTA6a
Line: 35-38 and 150
Thank you
The function is being called, but you are assigning to enemies and velocity in the function, so they are local to the function, and are then discarded when the function returns. So your function is called, but has no lasting effect.
You need to read about locals and globals in Python. As others point out you also have both Score and score here. Python is case-sensitive, those are different names.
You have if score >= 100 when you probably meant if Score >= 100. The function gets executed, it's just that the if statement always evaluates to false.
It's a scoping issue, the variables you're referring (enemies and velocity) to are created further down inside a while loop so they're not in scope in the function where you're trying to modify them. You need to read up on Execution model it should be able to clarify scoping rules.
Your code, paraphrased:
def game():
def levels(Score):
print 'levels!'
while start == True:
print 'start is indeed True!'
while not finish or falling:
'I am not Finnish'
for i in range(enemies):
'alas for I am beset by enemies!'
levels(score)
So, why isn't levels() being called? I suppose one of those many control flow items doesn't go the way you want. I can't say for example whether or not your enemies variable is empty but I can tell you that print is your friend.

Unbound Local error in Python I can't shake!

http://pastie.org/1966237
I keep getting an unbound local error. I don't understand why it occurs, if the program is running right, it should go straight into the second assignment of the print_et_list function within the main function, looping itself without actually looping. The program only quits using sys.exit() in the hey_user function.
I included the whole program for context, it isn't too long. Let me know if you want to have a look at the text files I use in the program, however I'm sure it's unlikely that it is the source of the problem.
UnboundLocalError happens when you read the value of a local variable before you set it. Why is score a local variable rather than a global variable? Because you set it in the function. Consider these two functions:
def foo():
print a
vs
def bar():
a = 1
print a
In foo(), a is global, because it is not set inside the function. In bar(), a is local. Now consider this code:
def baz():
print a
a = 1
Here, a is set within the function, so it's local. But it hasn't been set at the time of the print statement, so you get the UnboundLocalError.
You forgot to pass score into hey_user().
Looks like it's probably the score variable. It's a local in main(), but you try to reference it in hey_user().
If you want to make score a global variable, be sure to declare it with the global statement:
def main ():
global score
score = 0
question, solution = print_et_list()
scoresofar = hey_user (solution)
print "\nYour score is now", scoresofar
question, solution = print_et_list()

Categories