装饰器
1.装饰器入门
-
装饰器的作用:在不改变源代码和源代码调用方式的基础上,增加新的功能;
-
装饰器使用:
comment = decorator(comment)
@decorator
- 写法:
def decorator(fn): # fn=0x22
def inner(): # 0x33
print("请先登录...")
fn()
return inner # return 0x33
@decorator
def comment(): # 0x22
print("发表评论")
# comment = decorator(comment)
# comment是闭包对象=0x33
comment() # 0x33()
- 注意:语法糖写法,装饰器会在模块加载的那刻进行装饰。
2.装饰器的使用
- 装饰器实现已有函数执行时间的统计
# 使用装饰器统计函数的执行时间
import time
def decorator(fn):
def inner():
start = time.time()
fn()
end = time.time()
print("改函数执行共花费时间: ", (end-start))
return inner
@decorator # 等价于 foo=decorator(foo)
def foo():
for i in range(100000):
print(i)
if __name__ == '__main__':
foo()
3.通用装饰器
- 普通参数
def decorator(fn):
def inner(num1, num2):
print("扩展功能")
fn(num1, num2)
return inner
@decorator
def foo(a, b):
result = a + b
print("result: ", result)
- 可变参数
def decorator(fn):
def inner(*args, **kwargs):
print("扩展功能...")
fn(*args, **kwargs) # 拆包再传递参数
# fn(args, kwargs)
return inner
@decorator
def foo(*args, **kwargs):
print(args, kwargs)
result = 0
for i in args:
result += i
for i in kwargs.values():
result += i
print("result: ", result)
- 有返回值
def decorator(fn):
def inner(num1, num2):
print("扩展功能...")
result = fn(num1, num2)
return result
return inner
@decorator # foo=decorator(foo)
def foo(a, b):
result = a + b
return result
- 结论:内层函数的原型必须和被装饰函数一样。
- 通用装饰器
- 作用:可以装饰不定长参数的函数和有返回值的函数。
- 格式:
def decorator(fn):
def inner(*args, **kwargs):
print("扩展功能...")
result = fn(*args, **kwargs)
print("扩展功能")
return result
return inner
- 使用:
# 内层函数的结构应该和待装饰函数的结构一样
# 通用装饰器
def decorator(fn):
def inner(*args, **kwargs):
print("扩展功能...")
result = fn(*args, **kwargs)
print("扩展功能2...")
return result
return inner
@decorator
def foo(a, b):
result = a + b
print("result: ", result)
@decorator
def foo2(a, b):
result = a + b
return result
@decorator
def foo3(*args, **kwargs):
print(args, kwargs)
result = 0
for i in args:
result += i
for i in kwargs.values():
result += i
print("result: ", result)
@decorator
def foo4():
print("发表评论....")
if __name__ == '__main__':
# foo(10, 20)
# ret = foo2(10, 20)
# print("ret: ", ret)
# foo3(1, 2, 3, a=10, b=20)
foo4()
4.多重装饰器
-
多重装饰器:一个函数被多个装饰器装饰
-
装饰原则:
多个装饰器可以对函数进行多个功能的装饰,装饰顺序是由内到外的进行装饰,调用顺序正好相反。
-
代码:
def make_div(fn): # 0x11 fn=0x44
print("make_div被调用")
def inner(): # 0x55
print("make_div中的inner被调用")
return "<div>" + fn() + "</div>"
return inner
def make_p(fn): # 0x22 fn=0x33
print("make_p被调用")
def inner(): # 0x44
print("make_p中的inner被调用")
return "<p>" + fn() + "</p>"
return inner
@make_div # content = make_div(content) --> content = 0x55
@make_p # content = make_p(content) --> content = 0x44
def content(): # 0x33
print("源函数被调用")
return "人生苦短"
if __name__ == '__main__':
result = content() # 0x55()
print(result)
5.带有参数的装饰器
- 语法格式:
def logging(flag):
def decorator(fn):
def inner(*args, **kwargs):
print("扩展功能...")
if flag == "+":
print("努力做加法....")
elif flag == "-":
print("努力做减法....")
result = fn(*args, **kwargs)
return result
return inner
return decorator
@logging("+")
def add(a, b):
result = a + b
print("result: ", result)
@logging("-")
def sub(a, b):
result = a - b
print("result: ", result)
if __name__ == '__main__':
add(10, 20)
sub(100, 50)
6.类装饰器
-
作用:使用类来实现闭包
-
类的书写:
def init(self, fn):
def call(self, *args, **kwargs):
# 装饰器函数
# def func_out(fn):
#
# def func_in():
# print("请先登录")
# fn()
#
# return func_in
# @func_out
# def comment():
# print("发表评论")
# 类装饰器
class Check(object):
def __init__(self, fn): # fn=0x11
self.__fn = fn # self.__fn = 0x11
# self.__fn = 0x22
def __call__(self, *args, **kwargs):
print("请先登录")
result = self.__fn(*args, **kwargs)
return result
@Check # comment = Check(comment) --> comment 是 Check类的对象
def comment(): # 0x11
print("发表评论")
@Check # foo = Check(foo) --> foo 是 Check类的对象
def foo(a, b): # 0x22
result = a + b
return result
if __name__ == '__main__':
comment() # 对象() --> __call__(对象)
ret = foo(10, 20)
print(ret)