Python是如何知道函数的结尾在哪里的?

55

我正在学习Python,但是当一个函数的"def"结束时我感到困惑。

我看到像这样的代码示例:

def myfunc(a=4,b=6):
    sum = a + b
    return sum

myfunc()

因为我看到过类似 if FOO 就返回 BAR,否则返回 FOOBAR 的语句,所以我知道这个函数不会因为 return 而结束。Python 如何知道这不是一个递归函数调用自身?当函数运行时,它只是继续执行程序直到找到 return 吗?这可能导致一些有趣的错误。

谢谢


2
这是一个非常好的评论。任何关于Python的介绍都会提到显著的空格作为第一件事情,如果不是第一件的话 - 毕竟,这是最具特色的Python功能之一。 - Pavel Minaev
到目前为止,我只是使用这个速查表:http://www.ibm.com/developerworks/library/l-cheatsheet3.html来尝试学习语法。如果您有好的教程建议,我很乐意接受。 - Dan
1
谷歌一下教程,它们可能会更好一些。速查表中说:“代码块由以冒号(:)结尾的语句之后的缩进表示,例如…”因此它不会误导你。 - S.Lott
最好的Python入门书籍是《Dive Into Python》。 - Bartosz Radaczyński
认真思考一下为什么在 sum = a + b 前面有空格。你试过不在那里使用空格吗?如果这样做会发生什么?这能给一些暗示吗? - Karl Knechtel
8个回答

73

在Python中,空白字符是有意义的。当缩进变小(即减少)时,函数就结束了。

def f():
    pass # first line
    pass # second line
pass # <-- less indentation, not part of function f.

请注意,单行函数可以不缩进,在一行上写出:

def f(): pass

还有分号的使用,但不推荐使用:

def f(): pass; pass

以上三种形式展示了如何在语法上定义函数的结尾。至于语义,Python 中有三种退出函数的方式:

  • 使用 return 语句。这与你可能了解的其他命令式编程语言中的用法相同。

  • 使用 yield 语句。这意味着该函数是一个生成器,超出本答案的范围来解释它的语义,请查看 Can somebody explain me the python yield statement?

  • 仅仅通过执行最后一条语句退出函数。如果没有更多语句而且最后一条语句不是 return 语句,那么函数会像最后一条语句是 return None 一样退出。也就是说,如果没有明确的 return 语句,函数将返回 None。以下函数返回 None

def f():
    pass

而这个也一样:

def f():
    42

哎呀,这个语言太可怕了!难以维护。为什么不推荐使用分号?类型方面怎么样?它是如何知道52是'4'还是'52'的? - TomeeNS

37

Python对缩进非常敏感。一旦缩进级别回到函数定义的级别,函数就结束了。


6
哇...没有想到会这样。从未听说过缩进除了提高可读性之外还能用来做其他事情。谢谢! - Dan

10

准确地说,当一个缩进不大于开始位置的非空行遇到时,块就结束了。这个非空行不是该块的一部分。 例如,下面的打印同时结束了两个块:

def foo():
    if bar:
        print "bar"

print "baz" # ends the if and foo at the same time

缩进级别小于或等于def和if语句,因此它们都将结束。

没有语句的行,无论缩进如何,都不重要。

def foo():
    print "The line below has no indentation"

    print "Still part of foo"

但标记块结束的语句必须与任何现有缩进的级别相同。因此,以下是错误的:

def foo():
    print "Still correct"
   print "Error because there is no block at this indentation"

一般来说,如果你习惯于花括号语言,只需像它们那样缩进代码就可以了。

顺便说一下,“标准”的缩进方式是只用空格,但当然也可以只用制表符,但请不要混合使用。


为什么我要关心缩进?什么鬼? - TomeeNS

5
有趣的是,如果你只是在Python交互解释器中键入代码,那么你必须在函数后面加上一个空行。以下写法是不正确的:
def foo(x):
  return x+1
print "last"

虽然在文件中使用Python语法是完全合法的,但在与解释器交互时还存在其他语法差异,请注意。


1
我认为这是编写Python函数的理智方式。在没有空白行的情况下“取消缩进”似乎会带来麻烦。 - Andrew Wolfe
这不是解释器的“语法”差异,而是实际上的差异——唯一的原因是否则就没有办法在解释器中编写多行函数,并且解释器明确表示您仍在使用前导...编写函数定义的一部分。事实上,PEP8大致概述了在函数定义后应该或不应该有空行的情况。 - MoxieBall

2

空格很重要。当块结束时,函数定义也随之结束。

当函数运行时,它会一直运行直到完成,或者遇到returnyield语句为止。如果函数在没有遇到returnyield语句的情况下完成,则隐式返回None

教程中还有更多信息。


2

因此缩进很重要。正如其他用户在这里向您指出的那样,当缩进级别与def函数声明的位置相同时,您的函数已经结束。请记住,在Python中不能混合使用制表符和空格。大多数编辑器都提供此功能的支持。


1

它使用缩进

 def func():
     funcbody
     if cond: 
         ifbody
     outofif

 outof_func 

0
在我看来,最好通过注释显式标记函数的结尾。
def func():
     # funcbody
     ## end of subroutine func ##

问题在于某些子程序非常长,不方便滚动编辑器以检查哪个函数已经结束。此外,如果您使用Sublime,可以右键单击->转到定义,它将自动跳转到子程序声明。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接