This question already has answers here:
Python function returning None after recursion
(3个答案)
5年前关闭。
I have a question related to change in program behavior
。
。
通过下面的代码块,我得到的结果是4,即
。
Result: Count is 4
If I modify the above method so that the last statement does not contain
“return”语句我得到的结果是“None”。
结果:Count为None
(The version of Python I used is: 2.7.3)
上述行为是否是由于Python没有进行尾调用优化,或者是否涉及到任何其他推理?
A similar chunk of code in perl (which AFAIK doesn't do tail call optimization) provides
未将“return”作为最后一条语句的一部分的预期结果。
Result: Count is:4
。
我的问题是:
尾部调用优化是上面一段Python代码中显示的行为的原因。
如果是这样的话,那么perl代码的行为为什么不同,这也不影响TCO。
(3个答案)
5年前关闭。
I have a question related to change in program behavior
。
。
通过下面的代码块,我得到的结果是4,即
。
def count(x,acc=0):
if x==0:
return acc
return count(x/10,acc+1)
print "Count is %s" %(count(1234))
Result: Count is 4
If I modify the above method so that the last statement does not contain
“return”语句我得到的结果是“None”。
def count(x,acc=0):
if x==0:
return acc
count(x/10,acc+1)
print "Count is %s" %(count(1234))
结果:Count为None
(The version of Python I used is: 2.7.3)
上述行为是否是由于Python没有进行尾调用优化,或者是否涉及到任何其他推理?
A similar chunk of code in perl (which AFAIK doesn't do tail call optimization) provides
未将“return”作为最后一条语句的一部分的预期结果。
sub counter {
my ($n,$acc) = @_;
return $acc if ($n==0);
counter(int($n/10), $acc+1);
}
print "Count is:" . counter(1234,0) ."\n"
Result: Count is:4
。
我的问题是:
尾部调用优化是上面一段Python代码中显示的行为的原因。
如果是这样的话,那么perl代码的行为为什么不同,这也不影响TCO。
最佳答案
与尾部优化的缺失完全没有关系。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