繁体   English   中英

Python中的可变范围问题

[英]Variable Scope Issue in Python

我是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 ,对于ctr0ctr总是为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)

由于递归调用堆栈的顺序,示例中的变量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)

一个例子:

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

Python中的函数参数是按值传递的,而不是通过引用传递的。 如果将数字传递给函数,函数将接收该数字的副本。 如果函数修改了其参数,则该更改将在函数外部不可见:

def foo(y):
   y += 1
   print("y=", y) # prints 11

x = 10
foo(x)
print("x=", x) # Still 10

在您的情况下,最直接的解决方法是将ctr变为全局变量。 它非常难看,因为如果你想再次调用collat​​z函数你需要将全局重置为0,但是我只是为了表明你的逻辑是正确的,除了传递引用位之外。 (注意,collat​​z函数现在不返回任何内容,答案在全局变量中)。

ctr = 0
def collatz(num):
    global ctr
    if(num != 1):
        ctr+=1
        if(num%2==0):
                collatz(num/2)
        else:
                collatz(num*3+1)

ctr = 0
collatz(9)
print(ctr)

由于Python没有尾调用优化,如果collat​​z序列长度超过1000步,那么当前的递归代码将因堆栈溢出而崩溃(这是Pythons的默认堆栈限制)。 您可以通过使用循环而不是递归来避免此问题。 这也可以让我们摆脱那个麻烦的全局变量。 在我看来,最终的结果是更具惯用性的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 #???

变量将从你输入的任何数字开始返回最后一个collat​​z序列号.colltz猜想说这将永远是1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM