导语:本文章记录了本人在学习Python基础之函数篇的重点知识及我的心得,打算入门Python的朋友们能够来一块儿学习并交流。
本文重点:python
一、掌握装饰器的本质、功能和特色;
二、了解闭包的概念以及Python变量调用规则;
三、了解并学会使用标准库中重要的装饰器;
四、掌握参数化装饰器的意义和代码实现方式。
装饰器功能(decorator):将被装饰的函数看成参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数。
装饰器本质:是一个返回函数的高阶函数。
装饰器特色:缓存
一、多数装饰器会把被装饰的函数替换成其余函数
二、函数装饰器在导入模块时当即执行,而被装饰的函数只在明确调用时执行。
装饰器有时采用嵌套函数表示的缘由(我的理解):
一些装饰器的装饰功能只有在被装饰函数被调用时方可触发,所以须要用嵌套函数的形式来编写。闭包
自由变量(free variable):指未在本地做用域绑定的变量,介于局部变量和全局变量之间。
变量查找规则:在python中, 一个变量的查找顺序是 LEGB (L:Local 局部环境,E:Enclosing 闭包,G:Global 全局,B:Built-in 内建).函数
闭包:引用了自由变量的函数。学习
闭包的做用:ui
不一样的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时建立,通常程序执行完毕后做用域才释放。
nonlocal声明:能够将局部变量声明为自由变量。spa
eg:计算移动平均值的高阶函数:code
def averager(): sum=0 n=0 def avg(i): nonlocal sum,n sum+=i n+=1 return print(sum/n) return avg a=averager() a(3) a(5) a(7)
输出分别是3,4,5orm
Python内置了三个用于装饰方法的函数:property,classmethod和staticmethod
三个重要的内置装饰器:对象
能够把被装饰对象的相关属性复制到装饰器中
,默认有 __module__、__name__、__doc__。实现备忘功能,即缓存,避免发生重复调用来提升效率。
注意调用时必须带括号
,由于此装饰器包含maxsize和typed两个参数,带括号表示使用默认参数。不然 functools.lru_cache不清楚该如何执行。以functools.lru_cache为例实现斐波那契函数的计时装饰器:.
import time import functools def clock(func): @functools.lru_cache()#减小重复自引用,避免重复计算 def clocked(arg): t0=time.perf_counter() func(arg) result=func(arg) t1=time.perf_counter() processtime=t1-t0 name=func.__name__ print("[{0:.8f}] {1}({2})={3}".format(processtime,name,arg,result)) return result#很是重要,不然破坏原fibs函数致使没法递归调用。 return clocked @clock def fibs(n): if n<2: return 1 else: return fibs(n-1)+fibs(n-2) fibs(6)#输出8
如同函数能够嵌套使用,装饰器亦能够叠放起来装饰同一对象。语法以下:
@d1
@d2
def f1():
pass
上述装饰操做等价于d1(d2(f)),故易知叠放在上端的装饰器靠后执行。
普通装饰器的进阶版,经过参数接口能够更方便的定制咱们须要的装饰器,适应需求变化。代码实现较普通装饰器多嵌套一层函数,用来传递用户输入的参数。
以计时器举例形式以下:
import time DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args}) -> {result}' def clock(fmt=DEFAULT_FMT): #三层函数来实现 def decorate(func): def clocked(*_args): t0 = time.time() _result = func(*_args) elapsed = time.time() - t0 name = func.__name__ args = ', '.join(repr(arg) for arg in _args) result = repr(_result) print(fmt.format(**locals())) return _result return clocked return decorate if __name__ == '__main__': @clock() def snooze(seconds): time.sleep(seconds) for i in range(3): snooze(.123)
输出:
[0.12480044s] snooze(0.123) -> None [0.13660240s] snooze(0.123) -> None [0.12480044s] snooze(0.123) -> None
上边实现参数化装饰器的代码因为包含三重嵌套略显复杂, 事实上复杂的装饰器用 class 实现更方便。经过 __call__ 方法便可改写参数化装饰器。具体实现留做勤劳的你去课后思考,感兴趣的能够与我私信交流。