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

第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': {}}
    可以看到,函数包办了初始化的工作,让代码更易读。
    注意  字典的键并没有具体的顺序,所以当字典打印出来的时候,顺序是不同的。
  1. 如果我的参数不可变呢

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

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版·修订版)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值