关于迭代函数/通用函数的Python问题

huangapple go评论73阅读模式
英文:

python question about iterative functions/ general functions

问题

我有以下代码,我知道它是错误的,也知道错在哪里,缺少在两次迭代调用之前的 'return':

alpha = 546
beta = 66

def Euclid(a, b):
    while not (a == 0 or b == 0):
        if a >= b:
            Euclid(a % b, b)
        else:
            Euclid(a, b % a)

    return max(a, b)

print(Euclid(alpha, beta))

我的问题是为什么上面的代码仍然不起作用?我在代码可视化工具中查看它,它显示最后返回的值确实是max(a,b),也就是最大公约数 (GCD),但然后函数继续执行代码,无限循环从参数 (6,12) 变成 (6,0),然后再从 (6,12) 重新开始,返回 (6,0) 后。只想知道到底发生了什么,因为我以为函数总是在最后一个 return 后退出。

英文:

I have the following code, which i know to be wrong and also know what exactly is wrong, lack of 'return' before both iterative calls:

alpha = 546
beta = 66

def Euclid(a, b):
    while not (a == 0 or b == 0):
        if a >= b:
            Euclid(a % b, b)
        else:
            Euclid(a, b % a)

    return max(a, b)

print(Euclid(alpha, beta))

My question is why does the code above not still work? I viewed it in code visualiser, and it shows that the last value it returns is indeed max(a,b), so GCD, but then after the function keeps executing the code forever, going from arguments of (6,12) to (6,0), and then starting all over again with (6,12), after returning (6,0). Would just like to know what exactly is happening, since i thought function always quits after the last return.

答案1

得分: 1

让我们来看一下你的欧几里德函数,并逐行理解发生了什么(同时要密切关注变量的值):

def Euclid(a, b):
    while not (a == 0 or b == 0):
        if a >= b:
            Euclid(a % b, b)
        else:
            Euclid(a, b % a)

    return max(a, b)
  • 你使用a = 546和b = 66进行调用。(a=546和b=66)
  • 你进入while循环,因为a!=0且b!=0(a=546和b=66)
  • 由于a>=b,你调用Euclid函数,传入a%b和b(a=546和b=66)
  • 你忽略了返回值(a=546和b=66)(实际上,这个调用永远不会返回,但暂且假设它会返回)
  • 你回到while循环的开头,重新开始(a=546和b=66)

问题在于你从未修改a和b的值,因此你的while条件将永远为真,且函数的第一次调用永远无法达到返回语句。

附注:B Remmelzwaal关于修复你的代码的方法是正确的,我只是解释了发生了什么,导致你陷入无限循环。根据他的答案,正确的代码应该是:

def Euclid(a, b):
    while not (a == 0 or b == 0):
        if a >= b:
            return Euclid(a % b, b)
        else:
            return Euclid(a, b % a)

    return max(a, b)

附注2:为了澄清一些误解,代码中的while循环是不必要的,因为你只会进入一次循环然后返回。while循环内的命令永远不会重复执行。

更好地反映发生情况的代码是:

def Euclid(a, b):
    if a != 0 and b != 0:
        if a >= b:
            return Euclid(a % b, b)
        else:
            return Euclid(a, b % a)

    return max(a, b)

因此,当你使用a = 546和b = 66调用该函数时,将会发生以下情况:

  • Euclid(546,66)
    • Euclid(18,66)
      • Euclid(18,12)
        • Euclid(6,12)
          • Euclid(6,0) --> 这不再调用任何更多的Euclid,而是返回6
          • 返回6
        • 返回6
      • 返回6
    • 返回6
  • 返回6

因此,Euclid(6,0)给出6,Euclid(6,12)返回Euclid(6,0)的返回值,即6。以此类推,直到回到Euclid(546,66)。

你可以将其想象成一个套娃娃,每个外层娃娃告诉你内层娃娃告诉它的数字。在这个类比中,最小的内层娃娃是Euclid(6,0),而每个其他娃娃都会在通过各个层次时重复它的值。

英文:

Let's take a look at your Euclid function and try to understand what happens line by line (and also pay close attention to the values of the variables):

def Euclid(a, b):
    while not (a == 0 or b == 0):
        if a >= b:
            Euclid(a % b, b)
        else:
            Euclid(a, b % a)

    return max(a, b)
  • You call it with a = 546 and b = 66. (a=546 and b=66)
  • You enter the while loop because a!=0 and b!=0 (a=546 and b=66)
  • Since a>=b you call the Euclid function with a%b and b (a=546 and b=66)
  • You ignore the return value (a=546 and b=66) (actually this call never returns either, but let's assume for now it does)
  • You go back to the start of your while loop and start again (a=546 and b=66)

The problem is that you never modify the values of a and b, so your while condition will always be true, and your first call of the function never reaches the return.

Ps.: B Remmelzwaal is right about how to fix your code, I only explained what is happening, which makes you get stuck in an infinite loop. Based on his answer the correct code would be:

def Euclid(a, b):
    while not (a == 0 or b == 0):
        if a >= b:
            return Euclid(a % b, b)
        else:
            return Euclid(a, b % a)

    return max(a, b)

Ps2.: To clarify some misunderstanding, the while loop is un necessary in the code, since you would enter only once and return from it. The commands inside the while are never repeated.

The code which reflects better what is happening would be:

def Euclid(a, b):
    if a!=0 and b!=0:
        if a >= b:
            return Euclid(a % b, b)
        else:
            return Euclid(a, b % a)

    return max(a, b)

So in this case when you call the function with a = 546 and b = 66, the following is going to happen:

  • Euclid(546,66)
    • Euclid(18,66)
      • Euclid(18,12)
        • Euclid(6,12)
          • Euclid(6,0) --> This is not calling any more Euclids and returns 6
          • return 6
        • return 6
      • return 6
    • return 6
  • return 6

So the Euclid(6,0) gives you 6, the Euclid(6,12) returns the return value of Euclid(6,0), which was 6. And so on while you reach back to the Euclid(546,66).

You can imagine it as a matryoshka doll, every outer doll tells you the number which the inner doll told it. In this analogy the smallest inner doll is the Euclid(6,0) and every other doll just repeats it as it proceeds through the layers.

huangapple
  • 本文由 发表于 2023年2月8日 20:50:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75386055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定