Python中的变量作用域问题
我是Python新手,我已经使用它一段时间了,但是我遇到了一个问题。这是我的密码:Python中的变量作用域问题,python,recursion,call,callstack,Python,Recursion,Call,Callstack,我是Python新手,我已经使用它一段时间了,但是我遇到了一个问题。这是我的密码: def collatz(num,ctr): if(num != 1): ctr+=1 if(num%2==0): collatz(num/2,ctr) else: collatz(num*3+1,ctr) return ctr test=collatz(9,0) 对于我为num输入的任何数字,比如说9
def collatz(num,ctr):
if(num != 1):
ctr+=1
if(num%2==0):
collatz(num/2,ctr)
else:
collatz(num*3+1,ctr)
return ctr
test=collatz(9,0)
对于我为num
输入的任何数字,比如说9
,对于ctr
,ctr
总是显示为1
。我是否使用了ctr
变量错误
编辑:
我试图打印出函数的递归次数。因此,
ctr
将是每个递归的计数器 我更改了递归调用,将从递归调用接收的值设置回ctr。按照您编写它的方式,您正在丢弃从递归返回的值
def collatz(num,ctr):
if(num != 1):
ctr+=1
if(num%2==0):
ctr=collatz(num/2,ctr)
else:
ctr=collatz(num*3+1,ctr)
return ctr
test=collatz(9,0)
例如:
def collatz(number):
if number % 2 == 0:
print(number // 2)
return number // 2
elif number % 2 == 1:
result = 3 * number + 1
print(result)
return result
n = input("Give me a number: ")
while n != 1:
n = collatz(int(n))
变量将返回collatz序列的最终编号,从您输入的任何编号开始。collatz猜想说,由于递归调用堆栈的顺序,在您的示例中,变量
ctr
总是1
。当返回一个ctr
值时,调用堆栈将开始返回以前的ctr
值。基本上,在最后一次递归调用时,将返回ctr
的最高值。但由于调用堆栈底部的方法调用返回最后一个值,即将存储在test
中的值,test
将始终为1
。假设我将参数输入到collatz
,这将导致总共五次方法调用。调用堆栈看起来就像这样
collatz returns ctr --> 5
collatz returns ctr --> 4
collatz returns ctr --> 3
collatz returns ctr --> 2
collatz returns ctr --> 1 //what matters because ctr is being returned with every method call
如您所见,无论调用了多少次collatz
,都将始终返回1
,因为调用堆栈底部的调用具有ctr
均衡1
解决方案可能有很多,但它实际上取决于你试图实现的目标,而这在你的问题中没有明确说明
编辑:如果希望ctr
最终成为递归调用的次数,那么只需将ctr
赋值给方法调用的值即可。应该是这样的,
def collatz(num,ctr):
if(num != 1):
ctr+=1
if(num%2==0):
ctr = collatz(num/2,ctr)
else:
ttr = collatz(num*3+1,ctr)
return ctr
test=collatz(9,0)
Python中的函数参数是通过值传递的,而不是通过引用传递的。如果将数字传递给函数,该函数将收到该数字的副本。如果函数修改其参数,该更改在函数外部将不可见:
def foo(y):
y += 1
print("y=", y) # prints 11
x = 10
foo(x)
print("x=", x) # Still 10
在您的情况下,最直接的解决方法是将ctr变成一个全局变量。这非常难看,因为如果你想再次调用collatz函数,你需要将全局值重置回0,但是我展示这个替代方法只是为了证明你的逻辑是正确的,除了通过引用位。(注意collatz函数现在不返回任何内容,答案在全局变量中)
由于Python没有尾部调用优化,如果collatz序列超过1000个步骤(这是Pythons的默认堆栈限制),当前递归代码将因堆栈溢出而崩溃。您可以通过使用循环而不是递归来避免这个问题。这也让use摆脱了这个麻烦的全局变量。在我看来,最终的结果是Python更加惯用:
def collats(num):
ctr = 0
while num != 1:
ctr += 1
if num % 2 == 0:
num = num/2
else:
num = 3*num + 1
return ctr
print(collatz(9))
如果您想坚持使用递归函数,通常可以避免像您正在尝试的那样使用可变赋值。函数不是修改状态的“子例程”,而是使它们更接近数学函数,数学函数接收值并返回仅依赖于输入的结果。如果这样做的话,对递归进行推理就容易多了。我将把这作为一个练习,但递归函数的典型“框架”是有一个if语句来检查基本情况和递归情况:
def collatz(n):
if n == 1:
return 0
else if n % 2 == 0:
# tip: something involving collatz(n/2)
return #???
else:
# tip: something involving collatz(3*n+1)
return #???
预期的结果是什么?您希望通过此实现什么?
ctr=collatz(num//2,ctr)
。您还应该使用Python 3,/2
是浮点除法,/2
是整数除法。这是一样的,有什么区别吗?我更改了递归调用,将从递归调用接收的值设置回ctr
。您编写它的方式是丢弃从递归中得到的值。您应该在回答中解释,不是简单地从数学上给出代码,是的,但这不是此方法返回1的原因。函数应该返回达到1的步数。这与询问者所寻找的不完全一样。他的函数试图计算在达到1之前必须运行多少次。感谢您对递归工作原理的解释。我现在明白多了。我没有很好地解释我想在最终结果中解释什么,所以我将编辑这个问题。@Webtron请检查我的编辑,因为我认为它现在应该解决您的结果。
def collatz(n):
if n == 1:
return 0
else if n % 2 == 0:
# tip: something involving collatz(n/2)
return #???
else:
# tip: something involving collatz(3*n+1)
return #???