【问题标题】:python error - unboundLocalErrorpython错误 - unboundLocalError
【发布时间】:2011-11-17 18:54:30
【问题描述】:

我是编程新手,但我喜欢自然语言(如您所见)。我正在尝试编写一个简单的程序来帮助测试法语现在时动词。但是,在这段代码中,我不断收到一条错误消息,因为正确答案显然没有被设置为全局变量。有什么想法!?

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()

【问题讨论】:

    标签: python variables scope


    【解决方案1】:

    correctAnswers=0 超出范围。它们应该在getVerb 内。你也不需要递归。

    假设您想测试每个级别和每个问题一次:

    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()
    

    如果您可以通过预先分割部件或使用字典来控制您的 level1/level2 输入,则可以进一步优化。

    【讨论】:

    • 另外,您可能需要raw_input() 而不是input(),因为input() 将输入作为Python 执行,raw_input() 返回一个字符串。
    • 视情况而定。如果 OP 使用的是 Python2,那么是 如果是 Python3,那么不是。
    【解决方案2】:

    我已经清理了您的代码并使其更具 Python 风格。立即尝试:

    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()
    

    【讨论】:

      【解决方案3】:

      正如@Cixate 提到的,这可以通过设置correctAnswers = 0 inside getVerb 并用while循环替换递归来解决:

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

      问题在于 Python 实际上看到两个不同的变量,在两个不同的范围内,同名correctAnswer。这会导致发生称为“阴影”的事情。

      因此,Python 只会在getVerb 内部使用getVerbcorrectAnswers 版本。而且这个变量从未被赋予过价值!所以 Python 抱怨说你试图在没有分配它的情况下使用它。

      但是……等等!我们没有赋值吗?好吧,我们分配了一个名为 correctAnswers 的变量,但它是一个不同的变量,具有不同的范围。

      查看以下示例:

      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!"
      

      所以,总结一下疯狂:

      • y1 从外部作用域看到 x -- 在第一行声明
      • y2 创建自己的x -- 不能看到或使用另一个
      • y2自己的x 分配了一个新值并不重要,外部的x 仍然保持不变——参见outer 3outer 5
      • y3 也创建了自己的 x -- 但会在它有值之前尝试使用它 -> 崩溃并烧毁!!

      进行这一更改将使您的程序正常运行。尽管不是立即需要,但您最终可能希望提高代码质量,并学习如何编写更惯用的 Python 代码。例如:

      • 用 while 循环替换递归
      • 使用字典
      • 使用raw_input 而不是input

      但是,如果您继续努力,这会随着时间和经验自然而然地出现!

      【讨论】:

      • 很好地解释了范围。然而,移动correctAnswers 是不够的。递归会丢失correctAnswers 的总和,因为它每次都会重置它。您可以将 correctAnswers 作为参数传递给 getVerb() 以保持总和,但我认为仅此一项并不能体现 OP 想要的精神。
      【解决方案4】:

      在函数的开头,你可以告诉 Python correctAnswers 是一个全局变量:

      def getVerb():
          global correctAnswers
          ...
      

      祝你好运!

      【讨论】:

      • 我只注意到这里有一个 +1 和一个 -1 -- 如果有人知道我做错了什么,我将不胜感激!
      【解决方案5】:

      更 Python 的方法是使用生成器来获取当前级别的下一个问题:

      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
      

      【讨论】:

      • 如果可以,您当然应该避免使用global。几乎没有理由使用它。
      猜你喜欢
      • 2015-06-24
      • 1970-01-01
      • 2021-12-01
      • 2019-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      • 1970-01-01
      相关资源
      最近更新 更多