函数的定义和使用
函数的定义和使用的内容参看教程 4.6、4.7 节,语言手册 8.6 节)

一个函数定义包装起一段实现了某些计算过程的代码,使编程者可以在程序里的任何地方很方便地使用(实现)这个计算过程。函数定义可以包含参数,用于把计算里的一些具有通用性的元素提取出来,给予参数化,得到具有一定通用性的抽象计算过程。此后就可以通过提供具体参数的方式,用定义好的函数实现具体的计算。

换个说法,一个函数定义是一段计算过程的抽象,定义了一个抽象的(可能很复杂的)动作。在有这种定义之后,定义好的函数可以当作新的基本编程构件在程序里使用。

最简单的函数定义形式

Python 中函数定义的语法变化比较多,下面首先给出最基本的语法结构,后面逐步说明另外一些可用的结构细节。定义一个函数的最简单语法是:
	def 函数名 (参数表) : 语句组
这里的 "def 函数名 (参数表) :" 部分也称为函数的头部;“语句组”被称为函数体,是低一层的代码部分,需要采用“语句组”的标准写法(在换行之后退格书写)。“参数表”用括号括起,最简单的参数表是任意多个标识符(表示函数的参数,也称为“形式参数”)的序列,标识符之间用逗号分隔。也允许没有参数(“参数表”为空)的函数,这种函数称为"无参函数"。

我们把函数的参数看作是其函数体里的局部变量,如果在函数体里出现了“参数表”里列出的这些名字,就认为是在使用这个函数的参数。

函数调用

定义过的函数可以在随后的程序代码里调用。函数调用的基本形式是
	函数名(表达式, …, 表达式)
对于上面简单形式的函数定义,调用中括号里的表达式个数应该与函数参数的个数相同。

执行函数调用时,首先从左到有顺序计算出函数名后面括号里的各个表达式的值,把这些值按顺序约束到函数的各个(形式)参数,完成这些之后开始执行作为函数体的语句组。

函数里的 return 语句有特殊作用。在函数体执行中,一旦遇到了一个 return 语句,这个函数的本次执行结束。如果 return 有表达式部分,这时就计算这个表达式,并将计算得到的结果作为函数的返回值。如果该 return 语句无表达式部分,函数的返回值就是 None。如果函数体里的语句组执行完成(其中最后一个语句执行完成),该函数也以 None 作为返回值结束。

递归的函数定义

在一个函数定义里可以调用被定义的函数本身,这样的定义称为递归函数定义,如:
def power(x, n) :
    assert type(n) == int
    if n <= 0 :
        return 1
    else :
        return x * power(x, n - 1)
可以看到这个函数的体有两个语句,一个 assert 语句和一个 if 语句(它又包含两个段落,一个 if 段落和一个 else 段落),这两个语句在换行后退格并相互对齐。进一步,if 语句里嵌套的语句组也是换行后退格写出。

带默认值的参数

Python允许在定义函数时为一些参数指定默认值,形式上是在参数表里有关参数的后面写一个赋值符号和一个表达式。这样的表达式将在函数定义时求值,得到的值保存起来作为该函数参数的默认值。

在调用具有默认值参数的函数时,可以不为带默认的参数提供实际参数。如果调用式为带默认值的参数提供了实参,函数执行时就用这些实参的值;如果没提供就用函数定义中确定的默认值。

下面例子取值"Python 教程"

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise IOError('refusenik user')
                print(complaint)
这个函数向用户要求一个 yes/no 回答,它的执行将输出提示符(由用户通过函数的第一个参数提供),如果用户输入是 yes 或者 no 就返回逻辑值,否则输出一个"抱怨字符串"并重复。默认重复 4 次上面过程。这里的重复次数和"抱怨字符串"为带有默认值的参数。如果调用为
	ask_ok('Countinue? yes/no: ')
程序就会输出这个提示串,另外两个参数用默认值。如果调用:
	ask_ok('Countinue? yes/no: ', 3)
程序将输出提示符,试图取得用户的 yes/no 输入的工作只做 3 次。也可以在调用时提供一个抱怨字符串。如
	ask_ok('Countinue? yes/no: ', 3, 'No! I can\'t understand you!')
注意,带默认值的参数只能从后向前逐个缺省,下面写法就有问题
	ask_ok('Countinue? yes/no: ', 'No! I can\'t understand you!')
Python 会认为第二个字符串是提供给 retries 的实际参数。

关键字实参

在写函数调用时可以,指明调用式中给出的表达式的约束关系(指明其约束到哪个形式参数),这样的参数写法称为 "关键字实参"。在函数参数较多的情况下,这种写法有助于帮助看清调用式里的实际参数(表达式)和函数的形式参数之间的关系,还可以帮助解决上面默认值参数使用时的问题。

例如,下面的两个函数调用给出同样结果:

def f(x, y) :
    return x**y

print(f(2, 3))
print(f(y = 3, x = 2))
第一个调用的实际参数按位置匹配(简单情况),第二个调用按参数名匹配。

前面有关默认值参数的最后一个例子(那里的写法是一种调用错误)可以改为:

ask_ok('Countinue? yes/no: ', complaint = 'No! I can\'t understand you!')

文档串(documentation string或docstring)

Python 程序员经常在函数定义里用一个字符串文字量作为函数的第一个命令。显然,这种字符串的有无都不会影响函数的意义(由于没有把它赋给任何变量),它只是一种给读程序的人提供信息的方式。

这种字符串被称为 "文档字符串",人们用它说明函数的功能,提供帮助人理解和正确使用这个函数的有关信息。在写文档字符串时,人们经常采用三引号作为字符串的括号,因为这样的字符串可以延续多行,使用起来比较方便。

Python 教程的 4.6 节,4.7.6 节讨论了人们在这方面的一些想法和做法。

后面还会介绍函数的另外一些情况。

本页及相关页面(除另声明者外)由裘宗燕创建维护,可自由用于各种学习活动。其他使用需得到作者许可。