Why can't I access a global variable from inside a function?

money = 100
def play_game():
    pick_a_game = input('What game would you like to play: coin flip, pick a card, cho han, or roulette?')
    pick_a_game = pick_a_game.lower()
    if pick_a_game == 'coin flip':
        bet = int(input('Bet money!'))
        money += coin_flip(bet)
        print(f'Your current money is {money}')
    if pick_a_game == 'cho han':
        bet = int(input('Bet money!'))
        money += cho_han(bet)
        print(f'Your current money is {money}')
    if pick_a_game == 'pick a card':
        bet = int(input('Bet money!'))
        money += pick_a_card(bet)
        print(f'Your current money is {money}')
    if pick_a_game == 'roulette':
        bet = int(input('Bet money!'))
        money += roulette(bet)
        print(f'Your current money is {money}')

play_game()

Whenever I run my function it keeps throwing an UnboundLocalError, saying the local variable money is referenced before assignment. help!

Accessing it and modifying it are different, you can access a global variable from inside a function because you can use its value:

a = 10

def read_global():
  print(a) # this prints 10

However to modify a variable inside of a function you have to declare it as global inside the function:

a = 10

def modify_global():
  global a # tels the function to use the global variable a
  a += 10

modify_global()
print(a) # prints 20
3 Likes

Just a side note, do remember that it is better to use local variables whenever possible so that you can keep your global scope cleaner.

As you see in your code above, by having a global variable named money, you can no longer create a local variable named money because they would share the same name.

There are of course times when you have to use a global variable, but keep this in mind when you are working. :slightly_smiling_face:

2 Likes

Hi, how could I make the change to money permanent? It works now, but it keeps resetting to 100.

There are a couple of ways to do this. Usually the more efficient way depends on the functionality you envision your game growing into.

For games, I like to have player class(es) that can keep track of score, name, stats, etc.

Hmm… that’s a good idea. Would using return work?

You’d need to instantiate a player class (that you’d have to define as well) before play_game() is invoked.

player1 = Player("Bread Man")
play_game()

Then in the play_game() function your winning conditions can affect score or whatever:

if win:
   player1.score += 50
   return "{}'s score is now {}!!!".format(player1.name, player1.score)

#output, i'm pretending the original score was 8,951:
#Bread Man's score is now 9,001!!!
2 Likes

Wow! That’s really smart. Making a player class is super cool! Now, how to determine whether you win or lose?

That depends on the game. You’d probably need a while loop that only finishes when the winning condition is met so that you keep playing until you win or you quit (the quit option would involve calling a break on the loop).

while(not finished):
   play()
   if quit():
      break

#or

while(not finished and not quit):
   play()

1 Like

Hrmmm… I’m still stuck. I changed my games to incorporate my player class, but it still keeps resetting to 100.

If you share your code again we might be able to help :slight_smile:

import random

class Player:
    def __init__(self, name):
        self.name = name
        self.money = 100
        self.wins = 0
        self.losses = 0
    def __repr__(self):
        return f'{self.name} has {self.money} dollars and their stats are {self.wins} wins and {self.losses} losses.'

iParaDot = Player('iParaDot')

def coin_flip(bet, player):
    print('Playing coin flip!')
    if bet > 0 and bet <= player.money:
        coin_flip_result = random.randint(0,1)
        outcome = None 
        call = input('Pick a side!')
        call = call.lower().title()
        if call == 'Heads' or call == 'Tails':
            if coin_flip_result == 0:
                outcome = 'Heads'
                print(outcome)
            else:
                outcome = 'Tails'
                print(outcome)
    
            if outcome == call:
                print(f'You won! You earn {bet} dollars!')
                player.money += bet
            else:
                print(f'You lost! You lose {bet} dollars!')
                player.money += bet * -1
        else:
            print('Enter heads or tails!')
    else:
        print('Enter a postive number/enter within the range of your money!')

def cho_han(bet, player):
    print('Playing cho_han!')
    if bet > 0 and bet <= player.money:
        dice1 = random.randint(1,6)
        dice2 = random.randint(1,6)
        total = (dice1 + dice2) % 2
        call = input('Choose even or odd!')
        call = call.lower().title()
        if call == 'Even' or call == 'Odd':
            if total == 0:
                outcome = 'Even'
                print(outcome)
            else:
                outcome = 'Odd'
                print(outcome)
    
            if outcome == call:
                print(f'You won! You earn {bet} dollars!')
                player.money += bet
            else:
                print(f'You lost! You lose {bet} dollars!')
                player.money += bet * -1
        else:
            print('Enter even or odd!')
    else:
        print('Enter a postive number/enter within the range of your money!')

def pick_a_card(bet,player):
    print('Playing pick a card!')
    if bet > 0 and bet <= player.money:
        card_deck = ['Ace', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King']
        player_call = random.randint(0, len(card_deck)-1)
        computer_call = random.randint(0, len(card_deck)-1)

        player_choice = card_deck[player_call]
        print(f'You picked the card: {player_choice}')
        computer_choice = card_deck[computer_call]
        print(f'Player2 picked the card: {computer_choice}')
        if player_choice == 'Ace':
            player_choice = 1
        elif player_choice == 'Jack' or player_choice == 'Queen' or player_choice == 'King':
            player_choice = 10

        if computer_choice == 'Ace':
            computer_choice = 1
        elif computer_choice == 'Jack' or computer_choice == 'Queen' or computer_choice == 'King':
            computer_choice = 10

        if player_choice > computer_choice:
            print(f'You won! You earn {bet} dollars.')
            player.money += bet
        elif computer_choice > player_choice:
            print(f'You lost! You lose {bet} dollars.')
            player.money += bet * -1
        elif player_choice == computer_choice:
            print('A tie! You neither lose nor earn anything.')
            player_choice += 0
    else:
        print('Enter a postive number/enter within the range of your money!')

def roulette(bet,player):
    print('Playing roulette!')
    if bet > 0 and bet <= player.money:
        what_bet = input('What would you like to bet on? Choose: color, parity, or number.')
        what_bet = what_bet.lower()
        call = None
        if what_bet == 'color':
            call = input('Pick red or black!')
            call = call.lower().title()
        if what_bet == 'number':
            call = input('Pick a number from 1 to 37.')  
        if what_bet == 'parity':
            call = input('Pick odd or even!') 
            call = call.lower().title()
        even_or_odd = lambda num: 'Even' if num%2==0 else 'Odd'
        red_or_black = lambda num: 'Red' if num in red_numbers else 'Black'
        nums = range(1, 37)
        red_numbers = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]
        spin_dict = {}
        for num in nums:
            spin_dict[num] = even_or_odd(num), red_or_black(num)
        key = random.choice(list(spin_dict.keys()))
        b, c = spin_dict.get(key)
        spin = f'{key} {b, c}'
        print(spin)

        if type(call) != int:
            if call in spin:
                print(f'You won! You earn {bet} dollars.')
                player.money += bet
            else:
                print(f'You lost! You lose {bet} dollars.')
                player.money += bet * -1
        else:
            if call in spin:
                print(f'You won! You earn {bet * 35} dollars.')
                player.money += bet * 35
            else:
                print(f'You lost! You lose {bet} dollars.')
                player.money += bet * -1
    else:
        print('Enter a positive number/enter within the range of your money!')
      
def play_game(player):
    pick_a_game = input('What game would you like to play: coin flip, pick a card, cho han, or roulette?')
    pick_a_game = pick_a_game.lower()
    if pick_a_game == 'coin flip':
        bet = int(input('Bet money!'))
        coin_flip(bet,player)
        print(f"{player.name}'s current money is now {player.money}!")
    if pick_a_game == 'cho han':
        bet = int(input('Bet money!'))
        cho_han(bet,player)
        print(f"{player.name}'s current money is now {player.money}!")
    if pick_a_game == 'pick a card':
        bet = int(input('Bet money!'))
        pick_a_card(bet,player)
        print(f"{player.name}'s current money is now {player.money}!")
    if pick_a_game == 'roulette':
        bet = int(input('Bet money!'))
        roulette(bet,player)
        print(f"{player.name}'s current money is now {player.money}!")


play_game(iParaDot)

Should I put it on Github instead?

Do you remember the while-loop comment? It could work.

1 Like

Would I put that inside the play_game function?

probably within your individual games, watch out for infinite loops.

I can see how I could use the while loop, but I don’t see it solving my problem?

It would start and maintain a game loop, keeping track of player score until you win (and then a reset would make sense).

Hi, would I need to put the while loop surrounding the if statement that determines whether you won or lost, or put it around the entire code in my game functions?

you can do something like

def cho_han(bet, player):
   while(True):
      #game code
      if win_condition:
         break

Ok thanks that helps a lot. But as you saw, my if statements have else conditions that says what to do if you lost, or has the objective changed to just going until you win?