6.3 自定义函数
# 斐波那契数函数
def fibs(num):
result = [0, 1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
6.3.1 给函数编写文档
文档字符串(docstring)
下面的代码演示了如何给函数添加文
档字符串:
def square(x):
'Calculates the square of the number x.'
return x * x
可以像下面这样访问文档字符串:
>>> square.__doc__
'Calculates the square of the number x.'
注意 __doc__是函数的一个属性。属性将在第7章详细介绍。属性名中的双下划线表示这是一个特殊的属性。特殊(“魔法”)属性将在第9章讨论。
6.4 参数魔法
注意 参数存储在局部作用域内。
6.4.3 关键字参数和默认值
关键字参数最大的优点在于,可以指定默认值。
6.4.4 收集参数
允许提供任意数量的参数
def print_paras(*argv):
print(argvS)
- 参数前面的星号将所有实参都放在一个元组中,它收集的是列表而不是元组中多余的值。
- 星号收集余下的位置参数。如果没有可供收集的参数,params将是一个空元组。
- 带星号的参数也可放在其他位置,在这种情况下:需要使用名称来指定都需参数。
- 星号不会收集关键字参数。
>>> def in_the_middle(x, *y, z):
... print(x, y, z)
...
>>> in_the_middle(1, 2, 3, 4, 5, z=7)
1 (2, 3, 4, 5) 7
>>> in_the_middle(1, 2, 3, 4, 5, 7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: in_the_middle() missing 1 required keyword-only argument: 'z'
- 星号不会收集关键字参数。
>>> print_params_2('Hmm...', something=42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print_params_2() got an unexpected keyword argument 'something'
- 要收集关键字参数,可使用两个星号。
>>> def print_params_3(**params):
... print(params)
...
>>> print_params_3(x=1, y=2, z=3)
{'z': 3, 'x': 1, 'y': 2}
这样得到的是一个字典而不是元组。可结合使用这些技术。
6.4.5 分配参数
同样用(’* ‘和’ '),通过在调用函数时使用运算符实现。这种做法也可用于参数列表的一部分,条件是这部分位于参数列表末尾。通过使用运算符 **,可将字典中的值分配给关键字参数。
如果在定义和调用函数时都使用或,将只传递元组或字典。还不如不使用它们,还可省却些麻烦。
>>> def with_stars(**kwds):
... print(kwds['name'], 'is', kwds['age'], 'years old')
...
>>> def without_stars(kwds):
... print(kwds['name'], 'is', kwds['age'], 'years old')
...
>>> args = {'name': 'Mr. Gumby', 'age': 42}
>>> with_stars(**args)
Mr. Gumby is 42 years old
>>> without_stars(args)
Mr. Gumby is 42 years old
对于函数with_stars,在定义和调用它时都使用了星号,而对于函数without_stars,我在定义和调用它时都没有使用,但这两种做法的效果相同。因此,只有在定义函数(允许可变数量的参数)或调用函数(拆分字典或序列)时使用,星号才能发挥作用。
6.5 作用域
命名空间或作用域
- 全局作用域
- 每个函数调用都将创建一个
作用域嵌套(闭包)
python函数可以嵌套,即可将一个函数放在另一个函数内,嵌套通常用处不大,但有一个很突出的用途:使用一个函数来创建另一个函数。
def multiplier(factor):
def multiplyByFactor(number):
return number * factor
return multiplyByFactor
在这里,一个函数位于另一个函数中,且外面的函数返回里面的函数。也就是返回一个函数,而不是调用它。重要的是,返回的函数能够访问其定义所在的作用域。换而言之,它携带着自己所在的环境(和相关的局部变量)!
每当外部函数被调用时,都将重新定义内部的函数,而变量factor的值也可能不同。由于Python的嵌套作用域,可在内部函数中访问这个来自外部局部作用域(multiplier)的变量,如下所示:
>>> double = multiplier(2)
>>> double(5)
10
>>> triple = multiplier(3)
>>> triple(3)
9
>>> multiplier(5)(4)
20
像multiplyByFactor这样存储其所在作用域的函数称为闭包。
通常,不能给外部作用域内的变量赋值,但如果一定要这样做,可使用关键字nonlocal。这个关键字的用法与global很像,让你能够给外部作用域(非全局作用域)内的变量赋值。
6.6 递归
- 基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值。
- 递归条件:包含一个或多个调用,这些调用旨在解决问题的一部分。
map、filter、reduce
Python提供了一些有助于进行这种函数式编程的函数:map、filter和reduce。在较新的Python版本中,函数map和filter的用途并不大,应该使用列表推导来替代它们。你可使用map将序列的所有元素传递给函数。
>>> list(map(str, range(10))) # 与[str(i) for i in range(10)]等价
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
你可使用filter根据布尔函数的返回值来对元素进行过滤。
>>> def func(x):
... return x.isalnum()
...
>>> seq = ["foo", "x41", "?!", "***"]
>>> list(filter(func, seq))
['foo', 'x41']
6.7 本章介绍的新函数
函 数 | 描 述 |
---|---|
help(functionName) | 获取名为functionName函数的信息 |
callable(x) | 判断对象x是否可调用 |
map(func, seq[, seq, …]) | 对序列中的所有元素执行函数 |
filter(func, seq) | 返回一个列表,其中包含对其执行函数时结果为真的所有元素 |
reduce(func, seq[, initial]) | 等价于 func(func(func(seq[0], seq[1]), seq[2]), …) |
sum(seq) | 返回 seq 中所有元素的和 |
apply(func[, args[, kwargs]]) | 调用函数(还提供要传递给函数的参数) |
globals() | 返回一个包含全局变量的字典,类似于vars,globals()[‘parameter’]来访问名为parameter的全局变量 |
locals() | 返回一个包含局部变量的字典 |