2

下面的 Python 代码有一个奇怪的行为,我无法弄清楚。

程序调用 testQuery,它要求用户回答“是”以调用 scoreAverager,或“否”以退出程序。如果调用 scoreAverager,它会要求用户输入一系列分数,或“x”来完成,这会将用户返回到 testQuery,在那里他们可以选择对另一个测试进行平均或退出。

如果用户对几次测试(例如 2 次或更多)的结果进行平均,就会发生奇怪的事情。那时,对 testQuery 给出“否”将无法终止程序。它将为每个平均测试迭代一个额外的循环。我不明白为什么会这样。它看起来和行为都像一个错误的错误,但关闭循环的条件似乎已经满足。它可以通过“休息”来解决,但我宁愿知道更有机地解决它的问题是什么。

谁能让我知道为什么会发生这种奇怪的行为?

代码:

def scoreAverager():
    done=0
    scoreTot=0
    numScores=0
    average=0
    while done == 0:
        score=input("Enter the numerical score, or enter 'x' to finish entering scores:")
        acceptedXs={"X","x"}
        if score in acceptedXs:
            print ("The average of the scores is: ",average)
            #break #this break is necessary for proper function.
            done=1
            testQuery()
        else:
            try:
                score=float(score)
                scoreTot=scoreTot+score
                numScores=numScores+1
                average=scoreTot/numScores
            except ValueError:
                print("EXCEPTION: The entry was invalid, please try again.")

def testQuery():
    done=0
    while done == 0:
        moreTests=input("Do you have a set of score to average? Enter 'Yes' or 'No':")
        acceptedNos=("No","NO","no") 
        acceptedYess=("Yes","YES","yes")
        if moreTests in acceptedNos:
            print("Program Complete.")
            done=1
        elif moreTests in acceptedYess:
            scoreAverager()
        else:
            print ("ERROR: The entry was invalid. Please try again.") 

def main():
    testQuery()

main()    

输入/输出示例:

Do you have a set of score to average? Enter 'Yes' or 'No':Yes
Enter the numerical score, or enter 'x' to finish entering scores:1
Enter the numerical score, or enter 'x' to finish entering scores:2
Enter the numerical score, or enter 'x' to finish entering scores:x
The average of the scores is:  1.5
Do you have a set of score to average? Enter 'Yes' or 'No':Yes
Enter the numerical score, or enter 'x' to finish entering scores:1
Enter the numerical score, or enter 'x' to finish entering scores:2
Enter the numerical score, or enter 'x' to finish entering scores:x
The average of the scores is:  1.5
Do you have a set of score to average? Enter 'Yes' or 'No':No
Program Complete.
Do you have a set of score to average? Enter 'Yes' or 'No':No
Program Complete.
Do you have a set of score to average? Enter 'Yes' or 'No':No
Program Complete.
4

2 回答 2

0

我把你的代码剪掉了一点以隔离问题,嵌套了`scoreAvenger()`,并使范围问题更加明确。看起来,您实际上在这里所做的是间接递归:您调用一个不直接调用自身的函数,而是调用另一个调用它的函数。因此,您创建了一个复杂的递归调用堆栈,它必须自行展开。

这可以通过使用来解决,nonlocal但前提是我们适当地嵌套了函数;然后递归调用被终止[编辑:不!它们继续,但是 的值done没有设置为 0](因为嵌套函数捕获了 done 的值)。

def testQuery():
    def scoreAverager():
        nonlocal done       #here is the key: make done nonlocal 
        done = 0            #comment out above line to see the problem return
        while done == 0:
            score=input("Enter x")
            acceptedXs={"X","x"}
            if score in acceptedXs:
                print ("Returning to enclosing scope")
                done = True
                testQuery()
                print("stack unwinding in testQuery")


    done = 0
    while done == 0:
        moreTests=input("Want to enter nested scope/make another recursive call?")
        acceptedNos=("No","NO","no") 
        if moreTests in acceptedNos:
            print("Program Complete.")
            done = 1
        else:
            scoreAverager()
            print("stack unwinding in scoreAvenger")
def main():
    testQuery()

main()

这很棘手,我认为无论如何都是这样。编辑:添加了在递归调用离开堆栈后执行的打印函数。

于 2020-02-19T22:40:21.173 回答
0

问题很复杂,解决方案很简单。通过数十次调试代码,我认识到问题出在您的函数定义testQuery()行中。您在函数仍在运行时scoreAverager进入循环内部,这会使程序在两个运行循环中的值变为 1 时停止。testQuerydone

要解决这个问题,只需删除函数定义testQuery中的那一行,scoreAverager函数就会以与循环结束时相同的效率工作scoreAverager,它会返回到第一个启动的循环testQuery

于 2020-02-19T22:18:11.923 回答