0

I'm a newbie to programming but I am into natural languages (as you can see). I am trying to write a simple program to help test French present tense verbs. However, in this code I keep getting an error message because correctAnswers apparently hasn't been set as a global variable. Any ideas!?

import random

level1=["(manger)","je mange", "tu manges", "il mange", "elle mange", "nous mangeons", "vous mangez", "ils mangent", "elles mangent"]
level2=["(boire)", "je bois", "tu bois", "il boit", "elle boit", "nous buvons", "vous buvez", "ils boivent", "elles boivent"]

correctAnswers=0
blanks = '_' * 8

def getVerb():
    verbIndex=random.randint(1,len(level1)-1)
    print (level1[verbIndex].split()[0], blanks, level1[0])
    ans=input()
    while ans==level1[verbIndex].split()[1]:
        correctAnswers=correctAnswers+1
        print ("Nice one!")
        print (correctAnswers)
        getVerb()
    else:
        print ("Bad luck!")
        getVerb()


getVerb()
0

5 Answers 5

1

correctAnswers=0 is out of scope. They should be inside of getVerb. You also don't need recursion.

Assuming you want to test every level and every question once:

import random


level1=["(manger)","je mange", "tu manges", "il mange", "elle mange", "nous mangeons", "vous mangez", "ils mangent", "elles mangent"]
level2=["(boire)", "je bois", "tu bois", "il boit", "elle boit", "nous buvons", "vous buvez", "ils boivent", "elles boivent"]
blanks = '_' * 8

def getVerb():    
    correctAnswers = 0        

    # Do each level once
    for level in (level1, level2):
        level_name, choices = level[0], level[1:]

        # Shuffle the choices, this makes sure we only do each question once
        random.shuffle(choices)

        # Go through all the choices once
        for choice in choices:
            prefix, suffix = choice.split(' ', 2)
            print (prefix, blanks, level_name)

            ans = raw_input('Answer: ') # input() if Python 3
            while True:
                if ans == suffix:
                    correctAnswers += 1
                    print ("Nice one!")
                    print (correctAnswers)

                    # Got the right answer, break out
                    break
                else:
                    print ("Bad luck!")
                    # Change prompt to "Try again" on failure
                    ans = raw_input('Try again: ') # input() if Python 3


getVerb()

You could optimize this more if you had control of your level1/level2 input by pre-splitting the parts or by using a dict.

Sign up to request clarification or add additional context in comments.

2 Comments

Also, you probably want raw_input() and not input() as input() executes the input as Python and raw_input() returns a string.
It depends. If the OP is using Python2, then yes If Python3, then no.
1

I've cleaned up your code and made it a bit more Pythonic. Try it now:

import random

def getVerb():
    level1 = ["(manger)","je mange", "tu manges", "il mange", "elle mange", "nous mangeons", "vous mangez", "ils mangent", "elles mangent"]
    level2 = ["(boire)", "je bois", "tu bois", "il boit", "elle boit", "nous buvons", "vous buvez", "ils boivent", "elles boivent"]

    blanks = '_' * 8
    correctAnswers = 0
    randomElement = random.choice(level1)

    print(randomElement.split()[0], blanks, level1[0])

    ans = input()

    while True:
        if ans == randomElement.split()[1]:
            correctAnswers += 1

            print("Nice one!")
            print(correctAnswers)
        else:
            print("Bad luck!")

        ans = input()

if __name__ == '__main__':
    getVerb()

Comments

1

As @Cixate has mentioned, this can be fixed by setting correctAnswers = 0 inside getVerb and replacing the recursion with a while-loop:

def getVerb():
    correctAnswers = 0
    ... the rest of your code, as before ...
    ... making sure to replace the recursion with a while-loop ...

The problem is that Python actually sees two different variables, in two different scopes, with the same name of correctAnswer. This causes something called "shadowing" to happen.

Because of this, Python will only use getVerb's version of correctAnswers when inside getVerb. And this variable was never given a value! So Python complains that you're trying to use it without having assigned it.

But ... wait! Didn't we assign a value? Well, we assigned to a variable named correctAnswers, but it was a different variable, with a different scope.

Check out the following examples:

x = 3

print "outer 1:", x   # prints 3

def y1():
  print "in y1:", x   # print 3 -- !!

print "outer 2:", x   # still prints 3

def y2():
  x = 4
  print "in y2:", x   # prints 4 !!!

print "outer 3:", x   # prints 3 ????

def y3():
  print "in y3:", x   # raises an exception!
  x = 5

print "outer 4:", x   # prints 3

y1()

y2()

print "outer 5:", x   # still prints 3 !!!

try:
  y3()
except:
  print "y3 doesn't work!"

So, to sum up the craziness:

  • y1 sees the x from the outer scope -- declared on the first line
  • y2 creates its own x -- and can't see or use the other one
  • it doesn't matter that y2 assigned a new value to its own x, the outer x is still unchanged -- see outer 3 and outer 5
  • y3 also creates its own x -- but tries to use it before it has a value -> crash and burn!!

Making this one change will get your program working. Although it's not immediately necessary, you may eventually wish to improve your code quality, and learn how to write more idiomatic Python code. For example:

  • replace the recursion with a while-loop
  • use dictionaries
  • use raw_input instead of input

But this will come naturally with time and experience if you keep up the good work!

1 Comment

Good explanation of scope. However, moving correctAnswers wasn't enough. The recursion loses the sum of correctAnswers since it resets it every time. You could pass correctAnswers as a parameter to getVerb() to maintain the sum, but I don't think that alone captures the spirit of what the OP wanted.
0

At the beginning of your function, you can tell Python that correctAnswers is a global variable:

def getVerb():
    global correctAnswers
    ...

Good luck getting your verbs!

1 Comment

I just noticed both a +1 and a -1 here-- if anyone knows something I did wrong, I'd be grateful to learn!
-1

A more pythonic approach would be to use a generator to get the next question for the current level:

import random

levels = {
    '(manger)' : ["je mange", "tu manges", "il mange", "elle mange", "nous mangeons", "vous mangez", "ils mangent", "elles mangent"],
    '(boire)' : ["je bois", "tu bois", "il boit", "elle boit", "nous buvons", "vous buvez", "ils boivent", "elles boivent"]
}

def getVerb(words):
    random.shuffle(words)
    for verb in words:
        yield verb.split()

if __name__ == '__main__':

    blanks = '_' * 8
    correct = 0
    missed = 0

    for level, words in levels.items():
        for pronoun, verb in getVerb(words):
            print pronoun, blanks, level
            answer = raw_input('Answer: ')

            if answer == verb:
                correct += 1
                print 'Nice!'
            else:
                missed += 1
                print 'Missed =['

        print 'Level', level ,'Complete!', 'Correct:', correct, 'Missed:', missed
        print

1 Comment

You should of course avoid global if you can. There's hardly ever a reason to use it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.