1.4 设计函数
INFO
不管程序大小,函数都是核心组成部分,也是我们在编程语言里表达计算过程的主要媒介。前面我们讲了函数的形式特性和调用方式,现在换个话题:什么样的函数才算好。说到底,好函数的种种品质,都在强化同一个理念——函数即抽象。
- 每个函数只做一件事。这件事应该能用简短的名称概括,用一行话讲清。如果一个函数按顺序干好几件事,就拆成几个函数。
- 不要重复自己(Don't repeat yourself)。这是软件工程的一条核心信条。所谓 DRY 原则是说:多段代码不该重复描述同一套逻辑。逻辑只实现一次,起个名字,然后反复用。如果你在复制粘贴一段代码,那多半就是该做函数抽象了。
- 函数要定义得通用。比如,Python 库里就没有平方函数,因为它只是
pow函数的一个特例——pow能算任意次幂。
这些准则能让代码更好读、错误更少,通常还能少写不少代码。把复杂任务拆成简洁的函数,是需要经验才能练成的本事。好在 Python 提供了不少特性来帮你。
1.4.1 文档
函数定义里通常会带一段说明,叫文档字符串(docstring),它必须和函数体一起缩进。按惯例,文档字符串用三引号括起来。第一行用一句话说明函数干什么,后面的行可以交代参数、讲清函数的行为:
>>> def pressure(v, t, n):
"""计算理想气体的压力(单位:帕斯卡)
使用理想气体定律:http://en.wikipedia.org/wiki/Ideal_gas_law
v -- 气体体积,单位:立方米
t -- 绝对温度,单位:开尔文
n -- 气体粒子数
"""
k = 1.38e-23 # 玻尔兹曼常数
return n * k * t / v把函数名作为参数传给 help,就能看到它的文档字符串(在 Python 帮助界面里输入 q 退出):
>>> help(pressure)写 Python 程序时,除了最简单的函数,都该写文档字符串。记住:代码只写一次,却会被读很多次。Python 文档里有一套 文档字符串准则,用来保持不同项目之间的一致性。
注释。Python 的注释可以写在行尾,紧跟在 # 后面。比如上面那句「玻尔兹曼常数」,就是在说明变量 k。这些注释永远不会出现在 Python 的 help 里,解释器也会忽略它们——它们只给人看。
1.4.2 默认参数值
把函数定义得通用,一个后果就是参数变多。参数太多的函数,调用起来别扭,读起来也费劲。
在 Python 里,我们可以给函数的参数设默认值。调用时,带默认值的参数是可选的。不传的话,默认值就绑定到对应的形式参数名上。比如某个应用经常要算一摩尔粒子的压强,就可以把这个值设成默认值:
>>> def pressure(v, t, n=6.022e23):
"""计算理想气体的压强(单位:帕斯卡)。
v -- 气体体积,单位:立方米
t -- 绝对温度,单位:开尔文
n -- 气体粒子数(默认值:一摩尔)
"""
k = 1.38e-23 # 玻尔兹曼常数
return n * k * t / v这个例子里,= 符号在不同语境下有两种含义。在 def 语句头部(header),= 不是赋值,而是表示调用 pressure 时用的默认值。相比之下,函数体里对 k 的赋值语句,是把名称 k 绑定到玻尔兹曼常数的一个近似值上。
>>> pressure(1, 273.15)
2269.974834
>>> pressure(1, 273.15, 3 * 6.022e23)
6809.924502pressure 定义成接收三个参数,但上面第一个调用表达式只给了两个。这时 n 的值取自 def 语句里的默认值;如果给了第三个参数,默认值就被忽略。
一条准则是:函数体里用到的大部分数据,都该写成具名参数的默认值,既便于查看,也方便调用者修改。至于那些永不改变的值(比如基础常数 k),可以绑在函数体里或全局帧里。