python 装饰器 跟闭包
2018-06-20 本文已影响0人
VictorChi
使用python差不多已经有一年多了,回头来看.自己有很多地方没有理解,一直拖着直到现在.其中python中的装饰器跟闭包.这俩个概念就是如此.
今天是2018.06.20号周三,小目标是周五晚上24:00之前将本篇的博文整理出来.(失败周四到周日堕落了四天,尤其是周末),
不探讨别的就是把自己对于装饰器跟闭包的理解写下来.
其中探讨一下以下几个话题:
- 什么是闭包?
- 什么是装饰器?
- 它们之间有什么联系?
- python 是如何计算装饰器方法的?
- 闭包存在的原因和工作问题?
什么是闭包?
闭包指的是延伸了作用域的函数,其中包含函数定义体中引用,但是不在定义体中定义的非全局变量.函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量.
闭包
这里面有以下几点需要认清楚一下:
a = make_averager()
a(10) -----> 10
a(11) ----->10.5
a(12) ----->11
- 实例化
make_averager()
,你在运行的其实会调用里面的averager()
函数. series是一个可变对象,在averager()
之外,调用averager()
时它访问了在它本身定义的非全局变量series
.但是如果series
是一个不可变对象则会出错,函数averager
会将它变成一个局部变量,并且报错.
装饰器(decorate)
关于装饰器的小问题.
- 什么是装饰器?
装饰器仅仅是这样的函数:(通常)接受被装饰的可调用函数作为唯一参数,并返回一个可点用函数.
当装饰器应用到装饰函数时(而不是调用装饰器时),会执行装饰器代码本身 - 装饰器的功能是什么?
- 装饰器的的顺序。
装饰器的应用是自底向上 - 装饰器的本质。
- 何处使用装饰器?
如果使用一个类上的方法不需要这个这个类的实例,可以使用@classmethod 或者是@staticmethod装饰器。 - 编写装饰器的理由
装饰器提供了一种绝妙的方式来告知,"在指定的位置,我想要这个指定的可重复使用的功能片段" - 编写装饰器的时机.
- 数据的清理或添加
装饰器可以清理传递给被装饰器函数的参数的值.
装饰器可以改变或清除从函数中返回的数据. - 函数的注册.
- 数据的清理或添加
编写装饰器
执行时封装代码
这种装饰器非常简单,因为被装饰函数实在未经修改的条件下传递的.但是,执行被装饰方法时,可能希望运行额外的功能.为此,可以返回一个添加合适功能切在执行过程中调用被装饰方法的可调用函数.
一个简单的类型检查
def requires_ints(deocrated):
def inner(*args, **kwargs):
kwargs_values = [i for i in kwargs.values()]
for arg in list(args) + kwargs_values:
if not isinstance(arg, int):
raise TypeError('{} only accepts interges as arguments'.format(deocrated.__name__))
return deocrated(*args, **kwargs)
return inner
装饰器自身是requires_ints
.它接受一个参数:decorated
,即被装饰的可调用函数. 在这里装饰器唯一做的事情就是返回一个新的可调用的函数,即本地函数inner
.该函数代替了被装饰方法.
@requires_ints
def foo(x, y):
"""Return the sum of x and y."""
return x + y
运行help(foo)
Help on function inner in module __main__:
inner(*args, **kwargs)
将名称foo赋给inner函数,而不是赋给原来被定义的函数.
如果运行foo(3,5)
.
- 首先用传入的这个两个参数运行
inner
函数. -
inner
函数执行类型检查. - 然后运行被装饰的方法
- 简单的来说运行顺序为
- 装饰器在调用那一瞬间便已经运行了起来.在这里
foo
函数经过requires_ints
装饰器,已经变为inner
函数.(装饰器唯一做的事情就是返回一个新的可调用的函数) -
foo(3,5)
==>inner(3,5)
来验证传入的变量是否为integers
- 验证完成之返回
foo(3,5)
即8
,完成整个过程
- 装饰器在调用那一瞬间便已经运行了起来.在这里
保存帮助信息
装饰器时用于添加通用和可重复使用功能的工具,相对模糊的注释是有必要的,如果使用函数的人相对函数执行help,那么他只希望了解函数的核心信息,而不是关于shell
的信息.
@functools.wraps
的装饰器将一个函数中的重要内部元素复制到另一个函数.