|
| 1 | +# 1.3 定义新的函数 |
| 2 | + |
| 3 | +我们已经在 Python 中认识了一些在任何强大的编程语言中都会出现的元素: |
| 4 | + |
| 5 | +1. 数值是内建数据,算数运算是函数。 |
| 6 | +2. 嵌套函数提供了组合操作的手段。 |
| 7 | +3. 名称到值的绑定提供了有限的抽象手段。 |
| 8 | + |
| 9 | +现在我们将要了解函数定义,一个更加强大的抽象技巧,名称通过它可以绑定到复合操作上,并可以作为一个单元来引用。 |
| 10 | + |
| 11 | +我们通过如何表达“平方”这个概念来开始。我们可能会说,“对一个数求平方就是将这个数乘上它自己”。在 Python 中就是: |
| 12 | + |
| 13 | +```py |
| 14 | +>>> def square(x): |
| 15 | + return mul(x, x) |
| 16 | +``` |
| 17 | + |
| 18 | +这定义了一个新的函数,并赋予了名称`square`。这个用户定义的函数并不内建于解释器。它表示将一个数乘上自己的复合操作。定义中的`x`叫做形式参数,它为被乘的东西提供一个名称。这个定义创建了用户定义的函数,并且将它关联到名称`square`上。 |
| 19 | + |
| 20 | +函数定义包含`def`语句,它标明了`<name>`(名称)和一列带有名字的`<formal parameters>`(形式参数)。之后,`return`(返回)语句叫做函数体,指定了函数的`<return expression>`(返回表达式),它是函数无论什么时候调用都需要求职的表达式。 |
| 21 | + |
| 22 | +```py |
| 23 | +def <name>(<formal parameters>): |
| 24 | + return <return expression> |
| 25 | +``` |
| 26 | + |
| 27 | +第二行必须缩进!按照惯例我们应该缩进四个空格,而不是一个Tab,返回表达式并不是立即求值,它储存为新定义函数的一部分,并且只在函数最终调用时会被求出。(很快我们就会看到缩进区域可以跨越多行。) |
| 28 | + |
| 29 | +定义了`square`之后,我们使用调用表达式来调用它: |
| 30 | + |
| 31 | +```py |
| 32 | +>>> square(21) |
| 33 | +441 |
| 34 | +>>> square(add(2, 5)) |
| 35 | +49 |
| 36 | +>>> square(square(3)) |
| 37 | +81 |
| 38 | +``` |
| 39 | + |
| 40 | +我们也可以在构建其它函数时,将`square`用作构建块。列入,我们可以轻易定义`sum_squares`函数,它接受两个数值作为参数,并返回它们的平方和: |
| 41 | + |
| 42 | +```py |
| 43 | +>>> def sum_squares(x, y): |
| 44 | + return add(square(x), square(y)) |
| 45 | +>>> sum_squares(3, 4) |
| 46 | +25 |
| 47 | +``` |
| 48 | + |
| 49 | +用户定义的函数和内建函数以同种方法使用。确实,我们不可能在`sum_squares`的定义中分辨出`square`是否构建于解释器中,从模块导入还是由用户定义。 |
| 50 | + |
| 51 | +## 1.3.1 环境 |
| 52 | + |
| 53 | +我们的 Python 子集已经足够复杂了,程序的含义也不是非常明显。如果形式参数和内建函数具有相同名称会如何呢?两个函数是否能共享名称而不会产生混乱呢?为了解决这些疑问,我们必须详细描述环境。 |
| 54 | + |
| 55 | +表达式求值所在的环境由帧的序列组成,它们可以表述为一些合资。每一帧都包含了一些绑定,它们将名称和对应的值关联起来。全局帧只有一个,它包含所有内建函数的名称绑定(只展示了`abs`和`max`)。我们使用地球符号来表示全局。 |
| 56 | + |
| 57 | + |
| 58 | + |
| 59 | +赋值和导入语句会向当前环境的第一个帧添加条目。到目前为止,我们的环境只包含全局帧。 |
| 60 | + |
| 61 | +```py |
| 62 | +>>> from math import pi |
| 63 | +>>> tau = 2 * pi |
| 64 | +``` |
| 65 | + |
| 66 | + |
| 67 | + |
| 68 | +`def`语句也将绑定绑定到由定义创建的函数上。定义`square`之后的环境如图所示: |
| 69 | + |
| 70 | + |
| 71 | + |
| 72 | +这些环境图示展示了当前环境中的绑定,以及它们所绑定的值(并不是任何帧的一部分)。要注意函数名称是重复的,一个在帧中,另一个是函数的一部分。这一重复是有意的,许多不同的名字可能会引用相同函数,但是函数本身只有一个内在名称。但是,在环境中由名称检索值只检查名称绑定。函数的内在名称不在名称检索中起作用。在我们之前看到的例子中: |
| 73 | + |
| 74 | +```py |
| 75 | +>>> f = max |
| 76 | +>>> f |
| 77 | +<built-in function max> |
| 78 | +``` |
| 79 | + |
| 80 | +名称`max`是函数的内在名称,以及打印`f`时我们看到的名称。此外,名称`max`和`f`在全局环境中都绑定到了相同函数上。 |
| 81 | + |
| 82 | +在我们介绍 Python 的附加特性时,我们需要扩展这些图示。每次我们这样做的时候,我们都会列出图示可以表达的新特性。 |
| 83 | + |
| 84 | +**新环境特性:**赋值和用户定义的函数定义。 |
| 85 | + |
| 86 | + |
| 87 | + |
0 commit comments