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

时间:2014-02-26 14:51:56

标签: 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))

结果: 计数为4

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

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"

结果:计数为:4

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

我的问题是:

  • Tail Call优化是上述Python代码块中显示的行为的原因。
  • 如果是这种情况那么为什么perl代码的行为会有所不同,这也不会产生TCO。

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

没有return,这是唯一一种在acc == 0时返回内容的情况;对于您的count递归方法的任何其他调用,您不会返回任何内容,因此收到None

与其他语言(scala,显然也是perl,可能是其他语言)不同,python默认情况下不返回最后一个语句,你必须明确地调用return

答案 2 :(得分:2)

尾部调用消除不会阻止Perl的语义(虽然没有Perl语义,你的尾部调用会少得多,因为每个函数都会以return;隐式结束)。这纯粹是一种语言设计选择。 Perl和Python不同的原因是它们不是由同一个人设计的。

返回值的语法因语言选择而异。 Python的设计者选择了一个明确的return语句。在QBasic中,您必须分配值以返回与该函数具有相同名称的变量。

答案 3 :(得分:0)

没有return语句的Python函数返回值None

在这种情况下,您只会在x == 0时返回一个值,因此会得到None。有关详细信息,请查看Python教程:http://docs.python.org/2/tutorial/controlflow.html#defining-functions