浅析Python装饰器
admin
2023-07-31 00:46:22
0

Decorator(装饰器)是在写Python代码的过程中,经常会被用到的一个语言特性,它可以大幅度减少重复的模板代码,并且,对于已有代码的重构往往也有奇效。但是,实现一个Decorator时的重重嵌套函数定义,经常让人头晕。下面就以一个常见的函数Cache装饰器作为例子,浅析Python中的装饰器特性。

Decorator简介

首先要注意的是,Python在引入Decorator时,其实并没有引入任何新的语言特性,因为Decorator只是一种“语法糖”,不使用@decorator这样的语法,也完全可以使用Python的原有语法实现Decorator的功能。这得益于Python中一切皆是对象。对于这样的一个decorator:

123 @deco  def func():      pass

也就相当于:

123 def func():      pass  func = deco(func)

这种写法就像对原程序打了一个Monkey Patch。

Deocrator基本应用

无参数Decorator

下面用一个缓存函数返回值的Decorator说明其最基本的实现方式:

12345678910111213141516171819202122232425262728 # -*- coding: utf-8 -*- def func_cache(func): cache = {} def inner_deco(*args): if args in cache: print(\’func {} is already cached with arguments {}\’.format( func.__name__, args)) return cache[args] else: print(\’func {} is not cached with arguments {}\’.format( func.__name__, args)) res = func(*args) cache[args] = res return res return inner_deco @func_cachedef add_two_number(a, b): return a + b if __name__ == \”__main__\”: print(\’1. add_two_number(1, 2)\’) add_two_number(1, 2) print(\’2. add_two_number(2, 3)\’) add_two_number(2, 3) print(\’3. add_two_number(1, 2)\’) add_two_number(1, 2)

其中,func_cache就是我们实现的Decorator,它以一个函数对象(func)作为参数,返回另一个函数对象(inner_deco),因此,当我们每次调用被func_cache装饰过的函数(add_two_number)时,调用的其实是inner_deco,也即:

1 add_two_number(1, 2) > inner_deco(1, 2)

在这里,可以给出Decorator的一个粗浅定义:Decorator是一个函数,它以一个函数对象A为参数,返回另一个函数对象B。对象B定义在Decorator体内,形成一个闭包。函数A和函数B接受的参数相同。每当程序调用函数A时,实际上会转换为对函数B的调用。

再看inner_deco,它内部实现的就是函数返回值缓存的逻辑,并打印了一些调试信息。

但是这里有一个明显的问题:inner_deco只能接受*arg,也就是列表参数,这就限制了这个Decorator的使用范围。下面这个版本就添加了**kwargs的支持。需要注意的是,kwargs不能进行hash,也就不能直接作为python中字典的key值,因此这里现将其转成一个frozenset。

12345678910111213141516171819202122232425262728293031323334 # -*- coding: utf-8 -*- def func_cache(func): cache = {} def inner_deco(*args, **kwargs): key = (args, frozenset(kwargs.items())) if key an>kwargs.items())) if key 构往往也有奇效。但是,实现一个Decorator时的重重嵌套函数定义,经常让人头晕。下面就以一个常见的函数Cache装饰器作为例子,浅析Python中的装饰器特性。

Decorator简介

首先要注意的是,Python在引入Decorator时,其实并没有引入任何新的语言特性,因为Decorator只是一种“语法糖”,不使用@decorator这样的语法,也完全可以使用Python的原有语法实现Decorator的功能。这得益于Python中一切皆是对象。对于这样的一个decorator:

123 @deco  def func():      pass

也就相当于:

123 def func():      pass  func = deco(func)

这种写法就像对原程序打了一个Monkey Patch。

Deocrator基本应用

无参数Decorator

下面用一个缓存函数返回值的Decorator说明其最基本的实现方式:

12345678910111213141516171819202122232425262728 # -*- coding: utf-8 -*- def func_cache(func): cache = {} def inner_deco(*args): if args in cache: print(\’func {} is already cached with arguments {}\’.format( func.__name__, args)) return cache[args] else: print(\’func {} is not cached with arguments {}\’.format( func.__name__, args)) res = func(*args) cache[args] = res return res return inner_deco @func_cachedef add_two_number(a, b): return a + b if __name__ == \”__main__\”: print(\’1. add_two_number(1, 2)\’) add_two_number(1, 2) print(\’2. add_two_number(2, 3)\’) add_two_number(2, 3) print(\’3. add_two_number(1, 2)\’) add_two_number(1, 2)

其中,func_cache就是我们实现的Decorator,它以一个函数对象(func)作为参数,返回另一个函数对象(inner_deco),因此,当我们每次调用被func_cache装饰过的函数(add_two_number)时,调用的其实是inner_deco,也即:

1 add_two_number(1, 2) > inner_deco(1, 2)

在这里,可以给出Decorator的一个粗浅定义:Decorator是一个函数,它以一个函数对象A为参数,返回另一个函数对象B。对象B定义在Decorator体内,形成一个闭包。函数A和函数B接受的参数相同。每当程序调用函数A时,实际上会转换为对函数B的调用。

再看inner_deco,它内部实现的就是函数返回值缓存的逻辑,并打印了一些调试信息。

但是这里有一个明显的问题:inner_deco只能接受*arg,也就是列表参数,这就限制了这个Decorator的使用范围。下面这个版本就添加了**kwargs的支持。需要注意的是,kwargs不能进行hash,也就不能直接作为python中字典的key值,因此这里现将其转成一个frozenset。

12345678910111213141516171819202122232425262728293031323334 # -*- coding: utf-8 -*- def func_cache(func): cache = {} def inner_deco(*args, **kwargs):

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...