从0开始学python(4)

闭包

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False

f1()和f2()的调用结果互不影响。

练习
利用闭包返回一个计数器函数,每次调用它返回递增整数:

def createCounter():
    def counter():
        return 1
    return counter

测试:

counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')

答案

def createCounter():
    n = 0
    def counter():
        nonlocal n
        n += 1
        return n
    return counter


def createCounter():
    f = [0]
    def counter():        
        f[0] += 1
        return f[0]
    return counter

解释
nonlocal关键字:用来告诉内部函数,后边跟的变量需要到上一级函数里边去找,什么时候用?闭包内部函数需要修改外部函数的临时变量的时候
做一个类比就好理解了:

一个函数在函数内部要访问全局变量,当然可以,但是要修改全局变量(个人认为修改变量无外乎两种情况,可变对象原地修改;不可变对象新建一个对象,然后把变量指向新对象),很抱歉不可以。那用什么方法呢?
解决方法:a.加上global关键字 b.全局变量用可变对象,比如列表

同样的,闭包方便内部函数去获取外部函数的临时变量,但是不允许对其修改,要修改怎么办?
a.加nonlocal关键字声明一下 b.要修改的对象用可变对象储存!
这就是为什么有的答案用list有的答案用nonlocal

匿名函数
匿名函数lambda x: x * x实际上就是:

def f(x):
    return x * x

关键字lambda表示匿名函数,冒号前面的x表示函数参数。

装饰器
本质上,decorator就是一个返回函数的高阶函数。

以这道练习为例

请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:

代码如下

import time, functools
def metric(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kw):
        t_start = time.time()
        result = fn(*args, **kw)
        t_end = time.time()
        print('%s executed in %s ms' % (fn.__name__, t_end-t_start))
        return result
    return wrapper

可以看到wrapper里面先记录开始的时间,再调用原来的fn函数,最后记录结束的时间,用结束时间减去开始时间即运行时间

注意decorator返回的值是一个函数,若函数名为fast,则

@metric
def fast()

等价于

fast=metric(fast)

这样就做到了在不改变原函数结构的情况下添加了新的功能

猜你喜欢

转载自blog.csdn.net/weixin_42316707/article/details/88536213
今日推荐