4.6. 定义函数
我们可以创建一个输出任意范围内 Fibonacci 数列的函数:
- >>> def fib(n): # write Fibonacci series up to n
- ... """Print a Fibonacci series up to n."""
- ... a, b = 0, 1
- ... while a < n:
- ... print(a, end=' ')
- ... a, b = b, a+b
- ... print()
- ...
- >>> # Now call the function we just defined:
- ... fib(2000)
- 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字 def
引入一个函数 定义。它必须后跟函数名称和带括号的形式参数列表。构成函数体的语句从下一行开始,并且必须缩进。
函数体的第一个语句可以(可选的)是字符串文字;这个字符串文字是函数的文档字符串或 docstring 。(有关文档字符串的更多信息,请参阅 文档字符串 部分)有些工具使用文档字符串自动生成在线或印刷文档,或者让用户以交互式的形式浏览代码;在你编写的代码中包含文档字符串是一种很好的做法,所以要养成习惯。
函数的 执行 会引入一个用于函数局部变量的新符号表。 更确切地说,函数中所有的变量赋值都将存储在局部符号表中;而变量引用会首先在局部符号表中查找,然后是外层函数的局部符号表,最后是内置名称表。 因此,全局变量和外层函数的变量不能在函数内部直接赋值(除非是在 global
语句中定义的全局变量,或者是在 nonlocal
语句中定义的外层函数的变量),尽管它们可以被引用。
在函数被调用时,实际参数(实参)会被引入被调用函数的本地符号表中;因此,实参是通过 按值调用 传递的(其中 值 始终是对象 引用 而不是对象的值)。1 当一个函数调用另外一个函数时,将会为该调用创建一个新的本地符号表。
函数定义会把函数名引入当前的符号表中。函数名称的值具有解释器将其识别为用户定义函数的类型。这个值可以分配给另一个名称,该名称也可以作为一个函数使用。这用作一般的重命名机制:
- >>> fib
- <function fib at 10042ed0>
- >>> f = fib
- >>> f(100)
- 0 1 1 2 3 5 8 13 21 34 55 89
如果你学过其他语言,你可能会认为 fib
不是函数而是一个过程,因为它并不返回值。事实上,即使没有 return
语句的函数也会返回一个值,尽管它是一个相当无聊的值。这个值称为 None
(它是内置名称)。一般来说解释器不会打印出单独的返回值 None
,如果你真想看到它,你可以使用 print()
- >>> fib(0)
- >>> print(fib(0))
- None
写一个返回斐波那契数列的列表,而不是打印出来的函数,非常简单:
- >>> def fib2(n): # return Fibonacci series up to n
- ... """Return a list containing the Fibonacci series up to n."""
- ... result = []
- ... a, b = 0, 1
- ... while a < n:
- ... result.append(a) # see below
- ... a, b = b, a+b
- ... return result
- ...
- >>> f100 = fib2(100) # call it
- >>> f100 # write the result
- [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
此示例中,像往常一样,演示了一些新的 Python 功能:
return
语句会从函数内部返回一个值。 不带表达式参数的return
会返回None
。 函数执行完毕退出也会返回None
。result.append(a)
语句调用了列表对象result
的 方法 。方法是“属于”一个对象的函数,它被命名为obj.methodname
,其中obj
是某个对象(也可能是一个表达式),methodname
是由对象类型中定义的方法的名称。不同的类型可以定义不同的方法。不同类型的方法可以有相同的名称而不会引起歧义。(可以使用 类 定义自己的对象类型和方法,请参阅 类 )示例中的方法append()
是为列表对象定义的;它会在列表的最后添加一个新的元素。在这个示例中它相当于result = result + [a]
,但更高效。