函数是结构化编程的核心
自定义函数
一般而言,要判断某个对象是否可调用,可使用内置函数 callable
>>> import math
>>> x = 1
>>> y = math.sqrt
>>> callable(x)
False
>>> callable(y)
True
如何定义函数呢?
使用 def (表示定义函数)语句。
def hello(name):
return 'Hello, ' + name + '!'
运行这些代码后,将有一个名为 hello 的新函数。它返回一个字符串,其中包含向唯一参数指定的人发出的问候语。你可像使用内置函数那样使用这个函数。
>>> print(hello('world'))
Hello, world!
>>> print(hello('Gumby'))
Hello, Gumby!
很不错吧?如果编写一个函数,返回一个由斐波那契数组成的列表呢?很容易!只需使用前面介绍的代码,但不从用户那里读取数字,而是通过参数来获取。
def fibs(num):
result = [0, 1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
执行这些代码后,解释器就知道如何计算斐波那契数了。现在你不用再关心这些细节,而只需调用函数 fibs 。
>>> fibs(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
>>> fibs(15)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
在这个示例中, num 和 result 也可以使用其他名字,但 return 语句非常重要。 return 语句用于从函数返回值(在前面的 hello 函数中, return 语句的作用也是一样的)。
给函数编写文档
要给函数编写文档,以确保其他人能够理解,可添加注释(以#打头的内容)。还有另一种编写注释的方式,就是添加独立的字符串。在有些地方,如 def 语句后面(以及模块和类的开头,这将在第7章和第10章详细介绍),添加这样的字符串很有用。放在函数开头的字符串称为文档字符串(docstring),将作为函数的一部分存储起来。下面的代码演示了如何给函数添加文档字符串:
def square(x):
'Calculates the square of the number x.' #添加注释
return x * x
可以像下面这样访问文档字符串:
>>> square.__doc__
'Calculates the square of the number x.'
修改了变量关联到的列表。这很奇怪吧?其实不那么奇怪。下面再这样做一次,但这次不使用函数调用。
>>> names = ['Mrs. Entity', 'Mrs. Thing']
>>> n = names # 再次假装传递名字作为参数
>>> n[0] = 'Mr. Gumby' # 修改列表
>>> names
['Mr. Gumby', 'Mrs. Thing']
这样的情况你早就见过。将同一个列表赋给两个变量时,这两个变量将同时指向这个列表。就这么简单。要避免这样的结果,必须创建列表的副本。对序列执行切片操作时,返回的切片都是副本。因此,如果你创建覆盖整个列表的切片,得到的将是列表的副本。
>>> names = ['Mrs. Entity', 'Mrs. Thing']
>>> n = names[:]
现在 n 和 names 包含两个相等但不同的列表。
>>> n is names
False
>>> n == names
True
现在如果(像在函数 change 中那样)修改 n ,将不会影响 names 。
>>> n[0] = 'Mr. Gumby'
>>> n
['Mr. Gumby', 'Mrs. Thing']
>>> names
['Mrs. Entity', 'Mrs. Thing']
下面来尝试结合使用这种技巧和函数 change 。
>>> change(names[:])
>>> names
['Mrs. Entity', 'Mrs. Thing']
注意到参数 n 包含的是副本,因此原始列表是安全的。