Question

I'm having a little issue with my code, mainly (I think) with the try/except part. My code will generate a wordlist of the users choice. Here is the code:

def gen_wordlist():
    filename = input("Please enter the name of the wordlist:  ")

    try:
        my_file = open(filename, 'r')

    except FileNotFoundError:
        retry = input("No file named "+filename+". Would you like to try again (y/n)")
        if retry == 'y' or retry == 'Y':
            gen_wordlist()
        else:
            print("Goodbye :-)")
            sys.exit()

    words = my_file.read()
    my_file.close()
    return(words.split())


words = gen_wordlist()

If I enter a valid filename on the first attempt, it works as it should. However, if I enter an invalid filename and choose to try again, I get the following error, even if my second attempt is definitely a valid filename:

Traceback (most recent call last):
  File "TEST.py", line 20, in <module>
    words = gen_wordlist()
  File "TEST.py", line 15, in gen_wordlist
    words = my_file.read()
UnboundLocalError: local variable 'my_file' referenced before assignment

I can't work out why though. Surely, when I select 'y', the code just executes from the beginning of the gen_wordlist() function, and should work the same as if I had entered a valid filename on the first attempt, right?

Was it helpful?

Solution

If the open() call raises a FileNotFoundError exception, my_file was never set and all other references trying to use that name will fail.

That includes the code after gen_wordlist() was called in the exception handler. Sure, the new call may succeed, but that call then returns back to this frame where my_file was not set.

You want to return here too, instead:

if retry == 'y' or retry == 'Y':
    return gen_wordlist()

Otherwise you'll ignore the result of the successful recursive call here too.

It's not a great idea to use recursion to handle errors in user input. Use a loop instead:

my_file = None

while my_file is None:
    filename = input("Please enter the name of the wordlist:  ")

    try:
        my_file = open(filename, 'r')
    except FileNotFoundError:
        retry = input("No file named " + filename + ". Would you like to try again (y/n)")
        if retry.lower() == 'y':
            # back to the top of the loop
            continue

        print("Goodbye :-)")
        sys.exit()

This while loop then runs until my_file has successfully been set to a file object.

OTHER TIPS

Re-read the error message, it clearly says you have used the variable my_file before assignment. Now, look at your code, when do you define my_file in the except clause? The try falls out without declaring/assigning to the my_file variable in case of an error. Rest, Martijn's answer points out some more issues.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top