[英]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
,對於ctr
為0
, 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)
由於遞歸調用堆棧的順序,示例中的變量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變為全局變量。 它非常難看,因為如果你想再次調用collatz函數你需要將全局重置為0,但是我只是為了表明你的邏輯是正確的,除了傳遞引用位之外。 (注意,collatz函數現在不返回任何內容,答案在全局變量中)。
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沒有尾調用優化,如果collatz序列長度超過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 #???
變量將從你輸入的任何數字開始返回最后一個collatz序列號.colltz猜想說這將永遠是1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.