簡體   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