python的装饰器
1、装饰器的定义
给已有的函数添加额外功能的函数,它本质上就是一个闭包函数。
装饰器的功能特点:
- 不修改已有函数的功能特点
- 不修改已有函数的调用方式
- 给已有函数添加额外的功能
需求:给comment函数添加一个额外功能(需要先登陆,再评论)
要求:不能改变现有comment函数,不能修改comment函数的调用方式,还要添加一个额外功能
答:可以使用装饰器实现,装饰器的本质是一个闭包函数 =》① 有嵌套 ② 有引用 ③ 有返回
# 装饰器都有一个参数fn,代表要装饰函数的名称
def loggin(fn):
def inner():
# 在引用fn函数之前,添加额外功能
print('请先登陆!')
# 引用局部变量
fn()
return inner
@loggin
def comment():
print('发表评论:')
comment()
2、案例之给程序额外添加一个计算时间的功能
import time
def get_time(fn):
# 定义一个内部函数
def inner():
star = time.time()
# 有引用
fn()
end = time.time()
print(f'此程序执行了{(end - star):.02f}秒!')
# 返回内部函数的地址
return inner
@get_time # 在使用装饰器的时候自动将函数地址传给装饰器
def demo():
list1 = []
for i in range(10000000):
list1.append(i)
demo()
3、装饰器的执行原理
def logging(fn):
# fn = comment
def inner():
# 在引用fn函数之前,添加额外功能
print('请先登陆!')
# 引用局部变量
fn()
return inner
@logging # 这里相当于将comment的地址作为参数传给了logging
def comment():
print('发表评论:')
comment() # 并不是执行comment函数,而是执行logging函数的返回结果,inner函数
以下代码效果等同
def logging(fn):
def inner():
print('请先登陆!')
fn()
return inner
def comment():
print('发表评论')
# 等同于@logging 的效果
comment = logging(comment) # 为了满足装饰器的不能修改调用的方式的需求,这里使用同名变量
comment() # 这里调用的是inner函数,而不是comment函数,全局变量的优先级更大
4、装饰器修饰带有参数的函数
def message(fn):
# fn = sum_num
def inner(a, b): # 要修饰的函数带有参数
print('-----日志信息:正在努力计算中....-----')
fn(a, b) # fn(a, b) 等同于 sum_num(num1, num2)
return inner
@message
def sum_num(num1, num2):
print(num1 + num2)
# 这里实际调用的不是sum_num函数,而是inner函数,所以在inner函数中需要添加位置参数
sum_num(10, 20)
5、装饰器修饰带有不定长参数的函数
def message(fn):
def inner(*args, **kwargs):
print('----日志信息:正在努力计算....----')
fn(*args, **kwargs)
return inner
def sum_num(*args, **kwargs):
sum1 = 0
for i in args:
sum1 += i
for value in kwargs.values():
sum1 += value
print(sum1)
sum_num(10, 20, a=30, b=20)
6、装饰修饰带有返回值的函数
def message(fn):
def inner(num1, num2): # 在inner函数就没有返回,输出print()只能得到None
print('----输入日志:正在努力计算....----')
# fn(num1, num2) # =》 func(10,20) => 30 并不会得到返回值
return fn(num1, num2)
return inner
@message
def func(num1, num2):
result = num1 + num2
return result
print(func(10, 20)) # func(10,20) => inner(10,20) =>需要在inner函数输入返回值
7、(重点)通用装饰器的编写
① 有嵌套 ② 有引用 ③ 有不定长参数 ④ 有return返回值 ⑤ 返回内部函数的地址
def message(fn):
def inner(*args, **kwargs):
print('----日志信息:正在努力计算....----')
return fn(*args, **kwargs)
return inner
@message
def sum_num(num1, num2):
result = num1 + num2
return result
print(sum_num(10, 20))
8、带有参数的装饰器
定义:在使用装饰器 装饰函数的时候可以传入指定参数,让装饰器内部使用。
语法:@装饰器(参数....)
实现方法:由于装饰器函数只能有一个参数,就是被装饰函数引用,所以实现方法就是“将装饰器放进一个函数内部,外部函数接收参数,给装饰器使用。
def decoration(flag): # 再套入一层函数
def message(fn):
def inner(*args, **kwargs):
if flag == '+':
print('----输出日志:正在进行加法运算----')
elif flag == '-':
print('----输出日志:正在进行减法运算----')
return fn(*args, **kwargs)
return inner
return message # 都需要返回内层函数
@decoration('+')
def sum_num(num1, num2):
return num1 + num2
@decoration('-')
def sub_num(num1, num2):
return num1 - num2
print(sum_num(10, 20))
print(sum_num(20, 10))
9、类装饰器
类装饰器的编写规则:
① 必须要有一个__init__
初始化方法,用于接收要装饰函数的函数
② 必须要把这个类转化为可以调用的函数 ( __call__()
)
class Check(object):
# fn就是要装饰函数的名称,当Check装饰器类被调用时,系统自动将comment函数传递给comment变量
def __init__(self, fn):
self.__fn = fn
def __call__(self, *args, **kwargs):
# 编写装饰器代码
print('登陆功能')
# 调用comment函数本身
self.__fn(*args, **kwargs)
# 编写一个函数实现评论功能,底层comment = Check(comment)
@Check
def comment():
print('评论功能')
comment()
标签:comment,函数,python,print,inner,fn,装饰,def
From: https://www.cnblogs.com/luoluoange/p/17746619.html