搞定三大神器之 Python 装饰器

学会 Python 装饰器
装饰器,几乎各大Python框架中都能看到它的身影,足以表明它的价值!它有动态改变函数或类功能的魔力!

本专题的目录:

学会 Python 装饰器

1 什么是装饰器

2 装饰器的结构

3 为什么要这样

4 装饰一个函数

5 装饰一个类

6 装饰器层叠

7 温馨提醒

总结

扫描二维码关注公众号,回复: 11922104 查看本文章

1 什么是装饰器
对于受到封装的原函数比如f来说,装饰器能够在f函数执行前或者执行后分别运行一些代码。

2 装饰器的结构
装饰器也是一个函数,它装饰原函数f或类cls后,再返回一个函数g

装饰一个函数:

def decorator(f):

定义要返回的函数

def g():
print(‘函数f执行前的动作’)
f()
print(‘函数f执行后的动作’)
return g
装饰一个类:

def decorator(cls):

定义要返回的函数

def g():
print(‘类cls执行前的动作’)
f()
print(‘类cls执行后的动作’)
return g
使用装饰器很简单,@+自定义装饰器 装饰要想装饰的函数。

3 为什么要这样
要想理解装饰器为什么要有这种结构,要首先想明白装饰器的目标是什么。

它的价值在于为原函数f增加一些行为,前提必须不能破坏函数f,所以肯定不能改变f的内部结构,所以只能在调用f前后定义一些行为。

同时,装饰器函数decorator返回值又是什么?你可以思考下,返回一个函数是再好不过的了,它包装了原函数f.

4 装饰一个函数
printStar函数接收一个函数f,返回值也是一个函数,所以满足装饰器的结构要求,所以printStar是一个装饰器。

def printStar(f):
def g():
print(’*'20)
f()
print(’
'20)
return g
printStar装饰器实现f函数执行前、后各打印20个
字符。

使用printStar:

@printStar
def f():
print(‘hello world’)
调用:

if name == ‘main’:

改变函数功能

f()
打印结果:


hello world


可以很方便的装饰要想装饰的其他函数,如下:

@printStar
def g():
print(‘welcome to Python’)
5 装饰一个类
除了可以装饰函数f外,还可以装饰类cls,两者原理都是一样的。

下面给出一个装饰器实现单例模式的例子,所谓单例就是类只有唯一实例,不能有第二个。

def singleton(cls):
instance = {}

def get_instance(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return get_instance
定义字典instance,键值对分别为类和实例,这样确保只cls()一次。

使用装饰器singleton修饰类:

@singleton
class CorePoint:
pass
测试:

if name == ‘main’:

改变类的功能

c1 = CorePoint()
c2 = CorePoint()
print(c1 is c2) # True
6 装饰器层叠
上面原函数f不仅能被一个装饰器修饰,还能被n多个装饰器修饰。

下面再定义一个装饰器printLine,被修饰函数执行前后打印20个 -

def printLine(f):
def g():
print(’-’*20)
f()
print(’-’*20)
return g
使用上文定义好的printStar和printLine同时装饰函数f:

@printStar
@printLine
def f():
print(‘hello world’)
此时再调用函数f:

if name == ‘main’:

改变函数功能

f()
打印结果:



hello world


f被装饰后,先打印*,再打印 -

层叠多一层,原函数f就变强大一层。使用装饰器,还能实现功能抽离,进一步实现松耦合。

7 温馨提醒
打印原函数f的名字__name__,结果为f

In [1]: def f():
…: pass

In [4]: f.name
Out[4]: ‘f’
但是,被装饰后函数名字f变为g,这不是我们希望的!

@printStar
def f():
pass

f()
f.name # g
Python提供的解决方案:使用functools模块中的wraps装饰器:

from functools import wraps

def printStar(f):
@wraps(f)
def g():
print(’*‘20)
f()
print(’
’*20)
return g
此时再打印被装饰后f的名字,显示f,正常!
有相同爱好的可以进来一起讨论哦:企鹅群号:1046795523

学习视频资料:http://www.makeru.com.cn/live/1392_1164.html?s=143793

猜你喜欢

转载自blog.csdn.net/wy122222222/article/details/108756476