-2

I made a program to play hangman. I got pretty far but no matter how many times i try to fix it or make a different variation, the shell just comes up with the same thing.

UnboundLocalError: local variable '' referenced before assignment.

I'm fairly new so can you make the answers as simple as possible. (or just a de-bugged version).

import random
tries = 12
def intro ():
    print ('the size of your word is '+str(size))
    print ('you have ' + str(tries) + ' tries')
# word == car     output == '***'  
print (output)
def guesses ():
    guess = ('it')
    while len(guess) > 1:
        guess = str(input('pick a letter ')) 

if guess not in word:
    print ('incorrect')
    tries = tries - 1
    print ('you have ' + str(tries) + ' tries')

if guess in word:
    print ('correct!!')
    tries = tries - 1
    position = word.index(guess)
    output = output[:position] + guess + output[position+1:]
    print ('you have ' + str(tries) + ' tries')

print ('this is a game of hangman where you get a word')
print ('that you have to guess letter by letter')
print ('')
print ('')
word_list = ['jazz', 'whale', 'surgery', 'love']
word = random.choice(word_list)
size = len(word)
output = '*' * size
intro ()    

while output != word or tries != 0:
    guesses ()
    print (output)
roottraveller
  • 7,942
  • 7
  • 60
  • 65

3 Answers3

0

For starters, output is undefined. Note that you never assign to, or otherwise define output before you use it. Second, I can't help but to notice you try to use names defined inside of a function outside of it. There are two problems with this:

  • Names defined inside of a function do not belong to the global scope

  • Even if they did, function guesses executes after you've tried to use an undefined name guess

Take a look at this. I know coding is fun and it's tempting to start writing right away, but If this is your first programming language, don't rush it. If you go slowly and get the hang of Python ( or any other language, excluding some esoteric languages ), you'll be able to transition to any other language easily. Take it slow!

Transcendental
  • 983
  • 2
  • 11
  • 27
0

Apart for your snippet's indentation being off (remember that in python indentation is part of the syntax so take care about this when posting snippets), your main problem is with global vs local namespace.

The global namespace holds "top level" names (names defined at the top level of your script / module, IOW outside a function), the local namespace ("local" to a function's body) holds names defined within the function's body and the function's arguments if any.

When a name is used but not defined within a function's body, it is looked up in the global namespace, so a function can access names that have not been explicitely defined in it's local namespace.

BUT - and here comes the tricky part: "defined within the function's body" means there is an assignment to that name within the function (using one of "=", "+=", "-=", "/=" etc) anywhere in the function's body - the fact that there's a synonym in the global namespace doesn't magically make the name global, so if you really want to assign to a global name within a function (which is almost always a very bad idea, google "globals evil" for more on this), you have to explicitely tell Python this name should be considered global using the global statement, ie:

bar = 42

def foo():
   global bar
   bar = "baaz"

Trying to assign to global name without declaring it as global will always make the name local. If you don't try to access that name before the assignement, you will have no explicit error (the program is technically correct) but you may not have the expected result since the global name won't be affected (which a logical error, and usually harder to debug), ie:

>>> baaz = 42
>>> def foo():
...     baaz = 84
... 
>>> print(baaz)
42
>>> foo()
>>> print baaz
42
>>> 

But if you try to access the name before the line where it's defined, you will get this UnboundLocalError, because (by definition) before the assignment the (local) name is not bound to any value:

>>> baaz = 42
>>> def foo():
...     print(baaz) # wont print the global 'baaz' but raise an UnboundLocalError
...     baaz = 84 # because this line defines `baaz` as a local
... 
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'baaz' referenced before assignment

Now you can check your own code and find the at least three places where you do have this pattern (hint: in assignments, the right hand side of the = symbol is executed before the assignment itself).

You could (technically) "solve" this using the global statement but this is definitly not the right thing to do, at least if you hope to learn to write good (ie: readable, maintainable) code.

The good news is that you actually almost never have to modify a global variable (and I'm saying this from years of experience writing / maintaining real life full-blown applications) - you just have to 1/ pass relevant arguments to your functions and 2/ return relevant values from your functions. The top-level code of your scripts / module should only contains imports and functions / classes / constants defitions, and if it's a script a "main" function and a call to this function.

As an example here's a quick rewrite of your script without a single global variable - there's still a lot of room for improvement but at least it works, and it works without globals:

import random

def intro(tries, size):
    print ('the size of your word is {}'.format(size))
    print ('you have {} tries'.format(tries))

def guesses(word, tries, output):
    guess = ('it')
    while len(guess) > 1:
        guess = str(raw_input('pick a letter ')) 

    if guess not in word:
        print('incorrect')
        tries = tries - 1
        print('you have {} tries'.format(tries))

    else:
        print('correct!!')
        tries = tries - 1
        print('you have {} tries'.format(tries))
        position = word.index(guess)
        output = output[:position] + guess + output[position+1:]

    return tries, output

def main():
    print ('this is a game of hangman where you get a word')
    print ('that you have to guess letter by letter')
    print ('')
    print ('')
    word_list = ['jazz', 'whale', 'surgery', 'love']
    word = random.choice(word_list)
    size = len(word)
    output = '*' * size
    tries = 12

    intro(tries, size)    
    while not (output == word or tries == 0):
        tries, output = guesses(word, tries, output)
        print(output)

main()
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
-1

I think you are missing a global statement such as

def guesses ():
    global tries
    #... some of your code...
    #and now this line will work! :)
    tries = tries - 1

this kind of error usually comes up when you see code like this:

def f():
    x = x + 1

without a global statement

That said - try not to use global at all but to pass parameters to the function such as :

def guesses (tries):
    #now tries is a local variable and the next line works
    tries = tries - 1
Yoav Glazner
  • 7,936
  • 1
  • 19
  • 36
  • 1
    please dont teach newbies to use globals - better for them to not even know globals exist until they stumble on a problem that _really_ needs a global (which could never happen in whole life actually) – bruno desthuilliers Oct 10 '16 at 11:00
  • @brunodesthuilliers - Your point is valid, but this **is** the cause of his error ... I'll edit and suggest not to use *global* at all though – Yoav Glazner Oct 10 '16 at 11:04
  • 1
    I beg to differ on the "this (being) the cause of his error". Nothing in this code needs a global, so the "cause of his error" is actually trying to use names that are not defined in the *local* namespace ;-) – bruno desthuilliers Oct 10 '16 at 11:12