2014-02-26 18 views
2

我有一個程序行爲更改相關的問題 返回聲明導致在python方法中。python方法在沒有return語句中的行爲

count下面的方法打印給定整數中的位數。 用下面的代碼塊我得到的結果爲4,這是 預期的結果。

def count(x,acc=0): 
    if x==0: 
     return acc   
    return count(x/10,acc+1) 

print "Count is %s" %(count(1234)) 

結果:計數爲4

如果我修改了上面的方法,使最後的語句不包含 的「return」語句的結果我得到的是「無」。

def count(x,acc=0): 
    if x==0: 
     return acc   
    count(x/10,acc+1) 

print "Count is %s" %(count(1234)) 

結果:計數不是

(Python中的我使用的版本是:2.7.3)

請問上述行爲結果由於是Python並不做尾部呼叫優化還是還有其他推理嗎?

perl中的類似代碼塊(AFAIK不會執行尾部調用優化)提供了 預期結果,而'return'不是最後一條語句的一部分。

sub counter { 
    my ($n,$acc) = @_; 
    return $acc if ($n==0); 
    counter(int($n/10), $acc+1); 
} 
print "Count is:" . counter(1234,0) ."\n" 

結果:Count是:4

(Perl中的我上面的代碼塊跑的版本是:5.14.4和5.8.5)。

我的問題是:

  • 是尾部調用優化在Python代碼塊上面顯示的行爲的原因。
  • 如果是這種情況,那麼爲什麼perl代碼的行爲會有所不同,這也不會造成TCO。
+0

另請參閱http://stackoverflow.com/questions/17778372/why-does-my-python-function-return-none – devnull

+0

也http://stackoverflow.com/questions/15788969/python-function-always-returns-none – devnull

+1

一個更好的比喻可能是,如果Python在沒有顯式返回語句的情況下到達函數的末尾,就好像你沒有參數就「返回」。因此,你正在返回,但沒有指定返回值(返回None)。 – sabbahillel

回答

5

根本不需要做尾部優化。 Python中的函數需要顯式地使用關鍵字return,否則假定它們返回None

我知道Ruby沒有這樣的行爲,它返回最後執行的表達式的值。對於Perl,它必須是相同的。

它是什麼,聰明,只是一個事實,即Python程序行爲是那樣的:)

見兩個Python函數的拆卸。您可能會看到具有return值的那個實際上是如何調用該函數並將該值返回到堆棧頂部的。沒有它的那個,看到funciont調用之後有兩條指令,加載常量None並返回它。

def count(x,acc=0): 
    if x==0: 
     return acc   
    return count(x/10,acc+1) 

def count2(x,acc=0): 
    if x==0: 
     return acc   
    count(x/10,acc+1) 

In [7]: import dis  
In [8]: dis.dis(count) 
    2   0 LOAD_FAST    0 (x) 
       3 LOAD_CONST    1 (0) 
       6 COMPARE_OP    2 (==) 
       9 POP_JUMP_IF_FALSE  16 

    3   12 LOAD_FAST    1 (acc) 
      15 RETURN_VALUE 

    4  >> 16 LOAD_GLOBAL    0 (count) 
      19 LOAD_FAST    0 (x) 
      22 LOAD_CONST    2 (10) 
      25 BINARY_DIVIDE 
      26 LOAD_FAST    1 (acc) 
      29 LOAD_CONST    3 (1) 
      32 BINARY_ADD 
      33 CALL_FUNCTION   2 
      36 RETURN_VALUE 

In [9]: dis.dis(count2) 
    2   0 LOAD_FAST    0 (x) 
       3 LOAD_CONST    1 (0) 
       6 COMPARE_OP    2 (==) 
       9 POP_JUMP_IF_FALSE  16 

    3   12 LOAD_FAST    1 (acc) 
      15 RETURN_VALUE 

    4  >> 16 LOAD_GLOBAL    0 (count) 
      19 LOAD_FAST    0 (x) 
      22 LOAD_CONST    2 (10) 
      25 BINARY_DIVIDE 
      26 LOAD_FAST    1 (acc) 
      29 LOAD_CONST    3 (1) 
      32 BINARY_ADD 
      33 CALL_FUNCTION   2 
      36 POP_TOP 
      37 LOAD_CONST    0 (None) 
      40 RETURN_VALUE 
+2

我會告訴OP,缺少返回語句與沒有參數的「返回」類似。通過對其他語言進行類比,可以更容易地看到結果。 – sabbahillel

+0

@sabbahillel這也是一個很好的方式來看看它,謝謝指出! –

3

沒有return,唯一的情況下你的回報的東西,如果當acc == 0;對於任何其他調用您的count遞歸方法,您不返回任何內容,因此收到None

與其他語言不同(scala,顯然也可能是其他語言),python默認不會返回最後一條語句,您必須明確地調用return

2

尾調用消除並​​不妨礙Perl的語義(儘管沒有Perl語義,因爲每個函數都會隱含地以return;結尾,所以尾調用會少得多)。這純粹是一種語言設計選擇。 Perl和Python不同的原因是它們不是由同一個人設計的。

返回值的語法因語言而異,僅因選擇而異。 Python的設計者選擇要求明確的return聲明。在QBasic中,您必須分配該值以返回與該函數共享相同名稱的變量。