Python高级
Python高级-装饰器
装饰器
1. 装饰器的定义
就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数。
装饰器的功能特点:
1,不修改已有函数的源代码
2,不修改已有函数的调用方式
3,给已有函数增加额外的功能
2. 装饰器的示例代码:
# 添加一个登录验证的功能 def check(fn): def inner(): print("请先登录....") fn() return inner def comment(): print("发表评论") # 使用装饰器来装饰函数 comment = check(comment) comment() ''' 执行结果 请先登录.... 发表评论 ''' # 装饰器的基本雏形 # def decorator(fn): # fn:目标函数. # def inner(): # '''执行函数之前''' # fn() # 执行被装饰的函数 # '''执行函数之后''' # return inner
代码说明:
闭包函数有且只有一个参数,必须是函数类型,这样定义的函数才是装饰器。
写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。
3. 装饰器的语法糖写法
如果有多个函数都需要添加登录验证的功能,每次都需要编写func = check(func)这样代码对已有函数进行装饰,这种做法还是比较麻烦。
Python给提供了一个装饰函数更加简单的写法,那就是语法糖,语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰
# 添加一个登录验证的功能 def check(fn): def inner(): print("请先登录....") fn() return inner # 使用语法糖方式来装饰函数 @check def comment(): print("发表评论") comment() ''' 执行结果 请先登录.... 发表评论 '''
说明:
@check 等价于 comment = check(comment)
装饰器的执行时间是加载模块时立即执行。
4. 小结
装饰器本质上就是一个闭包函数,它可以对已有函数进行额外的功能扩展。
装饰器的语法格式:
# 装饰器 def decorator(fn): # fn:被装饰的目标函数. def inner(): '''执行函数之前''' fn() # 执行被装饰的目标函数 '''执行函数之后''' return inner
装饰器的语法糖用法: @装饰器名称,同样可以完成对已有函数的装饰操作。
5,代码实例:装饰器实现已有函数执行时间的统计
import time def get_time(func): start_time = time.time() func() end_time = time.time() run_time = end_time - start_time print('函数的执行时间是%s'%run_time) return get_time @get_time def test(): i = 0 for i in range(10000): print(i) i += 1 ''' 执行结果 0 1 2 3 ... 9996 9997 9998 9999 函数的执行时间是0.07971668243408203 '''
通过上面的示例代码可以得知装饰器的作用:
在不改变已有函数源代码及调用方式的前提下,对已有函数进行功能的扩展。
通用装饰器的使用
1. 装饰带有参数的函数
def logging(fn): def inner(num1, num2): print("--正在努力计算--") fn(num1, num2) return inner # 使用装饰器装饰函数 @logging def sum_num(a, b): result = a + b print(result) sum_num(1, 2) ''' 运行结果: --正在努力计算-- 3 '''
2. 装饰带有返回值的函数
# 添加输出日志的功能 def logging(fn): def inner(num1, num2): print("--正在努力计算--") result = fn(num1, num2) return result return inner # 使用装饰器装饰函数 @logging def sum_num(a, b): result = a + b return result result = sum_num(1, 2) print(result) ''' 运行结果: --正在努力计算-- 3 '''
3. 装饰带有不定长参数的函数
# 添加输出日志的功能 def logging(func): def inner(*args, **kwargs): print("--正在努力计算--") func(*args, **kwargs) return inner # 使用语法糖装饰函数 @logging def sum_num(*args, **kwargs): result = 0 for value in args: result += value for value in kwargs.values(): result += value print(result) sum_num(1, 2, a=10) ''' 运行结果: --正在努力计算-- 13 '''
4. 通用装饰器
# 添加输出日志的功能 def logging(func): def inner(*args, **kwargs): print("--正在努力计算--") result = func(*args, **kwargs) return result return inner # 使用语法糖装饰函数 @logging def sum_num(*args, **kwargs): result = 0 for value in args: result += value for value in kwargs.values(): result += value return result @logging def subtraction(a, b): result = a - b print(result) result = sum_num(1, 2, a=10) print(result) subtraction(4, 2) ''' 运行结果: --正在努力计算-- 13 --正在努力计算-- 2 '''
5. 小结
通用装饰器的语法格式:
# 通用装饰器 def logging(func): def inner(*args, **kwargs): print("--正在努力计算--") result = func(*args, **kwargs) return result return inner
多个装饰器的使用
多个装饰器的使用示例代码
def make_div(func): """对被装饰的函数的返回值 div标签""" def inner(): return "<div>" + func() + "</div>" return inner def make_p(func): """对被装饰的函数的返回值 p标签""" def inner(): return "<p>" + func() + "</p>" return inner # 装饰过程: 1 content = make_p(content) 2 content = make_div(content) # content = make_div(make_p(content)) @make_div @make_p def content(): return "人生苦短" result = content() print(result) # <div><p>人生苦短</p></div>
代码说明:多个装饰器的装饰过程是: 离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程
带有参数的装饰器
1. 带有参数的装饰器介绍
带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数,语法格式: @装饰器(参数,...)
错误写法:
def decorator(fn, flag): def inner(num1, num2): if flag == "+": print("--正在努力加法计算--") elif flag == "-": print("--正在努力减法计算--") result = fn(num1, num2) return result return inner @decorator('+') def add(a, b): result = a + b return result result = add(1, 3) print(result) ''' 执行结果: Traceback (most recent call last): File "/home/python/Desktop/pc/pc/apps/contents/tests.py", line 12, in <module> @decorator('+') TypeError: decorator() missing 1 required positional argument: 'flag' '''
代码说明:装饰器只能接收一个参数,并且还是函数类型。
正确写法:在装饰器外面再包裹上一个函数,让最外面的函数接收参数,返回的是装饰器,因为@符号后面必须是装饰器实例。
# 添加输出日志的功能 def logging(flag): def decorator(fn): def inner(num1, num2): if flag == "+": print("--正在努力加法计算--") elif flag == "-": print("--正在努力减法计算--") result = fn(num1, num2) return result return inner # 返回装饰器 return decorator # 使用装饰器装饰函数 @logging("+") def add(a, b): result = a + b return result @logging("-") def sub(a, b): result = a - b return result result = add(1, 2) print(result) result = sub(1, 2) print(result) ''' 执行结果: --正在努力加法计算-- 3 --正在努力减法计算-- -1 '''
2. 小结
使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回是装饰器,因为 @ 符号需要配合装饰器实例使用
类装饰器的使用
1. 类装饰器的介绍
装饰器还有一种特殊的用法就是类装饰器,就是通过定义一个类来装饰函数。
类装饰器示例代码:
class Check(object): def __init__(self, fn): # 初始化操作在此完成 self.__fn = fn # 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。 def __call__(self, *args, **kwargs): # 添加装饰功能 print("请先登陆...") self.__fn() @Check def comment(): print("发表评论") comment() ''' 执行结果: 请先登陆... 发表评论 '''
代码说明:
1.1@Check 等价于 comment = Check(comment), 所以需要提供一个init方法,并多增加一个fn参数。
1.2要想类的实例对象能够像函数一样调用,需要在类里面使用call方法,把类的实例变成可调用对象(callable),也就是说可以像调用函数一样进行调用。
1.3在call方法里进行对fn函数的装饰,可以添加额外的功能。
2. 小结
2.1想要让类的实例对象能够像函数一样进行调用,需要在类里面使用call方法,把类的实例变成可调用对象(callable)
2.2类装饰器装饰函数功能在call方法里面进行添加
最后修改:2020年3月7日 00:57