没有return语句的python方法的行为

sat*_*esh 2 python perl

我有一个与程序行为改变有关的问题,缺少return语句导致python方法.

下面的count方法打印给定整数中的位数.使用下面的代码块我得到结果为4,这是预期的结果.

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

print "Count is %s" %(count(1234))
Run Code Online (Sandbox Code Playgroud)

结果: 计数为4

如果我修改上面的方法,使最后一个语句不包含'return'语句,我得到的结果是'None'.

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

print "Count is %s" %(count(1234))
Run Code Online (Sandbox Code Playgroud)

结果:计数为无

(我使用的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"
Run Code Online (Sandbox Code Playgroud)

结果:计数为:4

(我在代码块上面运行的Perl版本是:5.14.4和5.8.5).

我的问题是:

  • 尾部调用优化是上面的Python代码块中显示的行为的原因.
  • 如果是这种情况那么为什么perl代码的行为会有所不同,这也不会产生TCO.

Pau*_* Bu 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
Run Code Online (Sandbox Code Playgroud)

  • 我会告诉OP,缺少return语句类似于没有参数的"return".通过对其他语言进行类比,可以更容易地看到结果. (2认同)