您的位置:首页 > 编程语言 > Python开发

《Python基础教程》读书笔记(1)之第6章抽象(关键词:Python/抽象/函数/参数/作用域)

2017-09-14 13:45 573 查看

第6章 抽象

6.3 创建函数

6.3.1 记录函数

如果在函数的开头写下字符串,它就会作为函数的一部分进行存储,称为“文档字符串”。
如下代码演示了如何给函数添加文档字符串:


def fibs(num):
'i am a fib function'
result = [0, 1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result


文档字符串可以按如下方式访问:


>>> fibs.__doc__
'i am a fib function'


注意 `__doc__`是函数属性。

内建的help函数是非常有用的。在交互式解释器中国使用它,可以得到关于函数,包括它的文档字符串的信息:


>>> help(fibs)
Help on function fibs in module __main__:

fibs(num)
i am a fib function


6.4 参数魔法

6.4.2 我能改变参数吗

在函数内为参数赋予新值,不会改变任何外部变量的值:


>>> def try_to_change(n):
...      n = 'gumby'
...
>>> name = 'henry'
>>> try_to_change(name)
>>> name
'henry'


在try_to_change内,参数n获得了新值,但是它没有影响到name变量。n实际上是个完全不同的变量,具体的工作方式类似于下面:


>>> name = 'henry'
>>> n = name
>>> n = 'gumby'
>>> name
'henry'


当变量n改变的时候,变量name不变。
同样,当在函数内部把参数重绑定(赋值)的时候,函数外的变量不会受到影响。
注意  参数存储在局部作用域(local scope)内。
字符串(以及数字和元组)是不可变的,即无法修改(也就是说只能用新的值覆盖)。


1. 为什么我想修改参数

抽象的要点就是隐藏更新时的繁琐的细节,这个过程可以用函数实现。
下面的例子就是初始化数据结构的函数:


>>> def init(data):
...     data['first'] = {}
...     data['middle'] = {}
...     data['last'] = {}


上面的代码只是把初始化语句放到了函数中,使用方法如下:


>>> storage = {}
>>> init(storage)
>>> storage
{'middle': {}, 'last': {}, 'first': {}}


可以看到,函数包办了初始化的工作,让代码更易读。
注意  字典的键并没有具体的顺序,所以当字典打印出来的时候,顺序是不同的。


如果我的参数不可变呢

函数只能修改参数对象本身。


6.4.4 收集参数

*的意思是“收集其余的位置参数”。


>>> def print_params_2(title, *params):
...     print title
...     print params
...
>>> print_params_2('Params:', 1, 2, 3)
Params:
(1, 2, 3)


但是,不能处理关键字参数:


>>> print_params_2('...', 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_4(x, y, z=3, *pospar, **keypar):
...     print x, y, z
...     print pospar
...     print keypar
...
>>> print_params_4(1, 2, 3, 5, 6, 7, foo=1, bar=2)
1 2 3
(5, 6, 7)
{'foo': 1, 'bar': 2}


6.5 作用域

可以把变量看作是值的名字。在执行x=1赋值语句后,名称x引用到值1。这就像用字典一样,键引用值。变量和所对应的值用的是个“不可见”的字典。实际上这么说已经很接近真实的情况了。内建的vars函数可以返回这个字典:

>>> x = 1
>>> vars()
{'me': 'magnus lie hetland', 'x': 1, 'name': 'henry', 'power': <function power at 0x7fbb03b94b90>, '__builtins__': <module '__builtin__' (built-in)>, 'storage': {'middle': {}, 'last': {}, 'first': {}}, 'try_to_change': <function try_to_change at 0x7fbb03b94938>, '__package__': None, 'init': <function init at 0x7fbb03b949b0>, 'lookup': <function lookup at 0x7fbb03b94a28>, 'print_params_4': <function print_params_4 at 0x7fbb03b94b18>, '__name__': '__main__', 'n': 'gumby', '__doc__': None, 'print_params_2': <function print_params_2 at 0x7fbb03b94aa0>}
>>> vars()['x']
1
>>> scope = vars()
>>> scope['x']
1
>>> scope['x'] += 1
>>> x
2


警告 一般来说,vars所返回的字典是不能修改的,因为根据官方的Python文档的说法,结果是未定义的。换句话说,可能得不到想要的结果。

这类“不可见字典”叫做命名空间或者作用域。那么到底有多少个命名空间?除了全局作用域外,每个函数调用都会创建一个新的作用域:


嵌套作用域

闭包(closure)


6.6 递归

6.6.2 另外一个经典:二元查找

实现一个二分查找算法:

# biSearchDemo.py
def search(sequence, number, lower, upper=None):
if upper is None:
upper = len(sequence) - 1
if lower == upper:
assert number == sequence[upper]
return upper
else:
middle = (lower + upper) // 2
if number > sequence[middle]:
return search(sequence, number, middle+1, upper)
else:
return search(sequence, number, lower, middle)


提示 标准库中的bisect模块可以非常有效地实现二元查找。

参考文献:

1.《Pytho基础教程(第2版·修订版)》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐