# -*- coding: utf-8 -*- def test1(*args, **kwargs): print(f"这是额外的位置参数: {args}") print(f"这是额外的关键字参数: {kwargs}") t = (‘a‘, ‘b‘) d = {‘c‘: ‘c‘, ‘d‘: ‘d‘} # *表示对元素解包; **表示对字典解包 test1(*t, **d) # 等价于: test1("a", "b", c="c", d="d")
# -*- coding: utf-8 -*- def test1(): def inner1(m, n): return m + n return inner1 def test2(m): def inner2(n): return m + n return inner2 # [test1函数]不是闭包函数 print(test1.__closure__) # 运行结果: None # [test1函数]内的[inner1函数]是闭包函数 inner1 = test1() print(inner1.__closure__) # 运行结果: None # [test2函数]不是闭包函数 print(test2.__closure__) # 运行结果: None # [test2函数]内的[inner2函数]是闭包函数 inner2 = test2(5) print(inner2.__closure__) # 运行结果: (<cell at 0x02FED430: int object at 0x7989D470>,)
2.1 装饰器是python中一类比较有特色的语法, 用来装饰函数和类
2.2 装饰器在不破坏原有函数结构的情况下, 可以进行功能扩展
2.2 使用装饰器, 可以增加代码的可读性, 让代码层次结构变得更加清晰
实现代码:
# -*- coding: utf-8 -*- # 被装饰函数 def myfunc(): return "hello chinablue!" # 装饰器: 在函数执行前 def mylog(func): def inner(): print(f"这是执行函数前打印的信息") return func() return inner print(mylog(myfunc)())
执行结果:
这是执行函数前打印的信息
hello chinablue!
实现功能:
同一个装饰器可以装饰参数个数不同的函数
实现代码:
# -*- coding: utf-8 -*- # 被修饰函数1 def myfunc1(a, b): return a + b # 被修饰函数2 def myfunc2(a, b, c): return a + b + c # 装饰器 def mylog(func):
# 运用可变参数后, 可以装饰任何带参数的函数 def inner(*args, **kwargs): res = func(*args, **kwargs) print(f"执行结果为: {res}") return res return inner # myfunc1函数: 2个必填参数 mylog(myfunc1)(1, 2) # myfunc2函数: 3个必填参数 mylog(myfunc2)(1, 2, 3)
执行结果:
执行结果为: 3
执行结果为: 6
实现代码:
# -*- coding: utf-8 -*- # 装饰器 def mylog(func): def inner(*args, **kwargs): res = func(*args, **kwargs) print(f"执行结果为: {res}") return res return inner @mylog def add(a, b): return a + b # 没有改变函数的调用方式 add(1, 2)
执行结果:
执行结果为: 3
对于上述代码, 当我们打印add函数的一些属性时, 会发现得到的属性信息并不是我们所期望的
# 打印函数的属性 print(f"add.__name__") # 执行结果: inner print(f"add.__doc__") # 执行结果: None
改进代码:
# -*- coding: utf-8 -*- from functools import wraps # 装饰器 def mylog(func): # 可以借助functools.warps函数, 避免属性篡改问题 @wraps(func) def inner(*args, **kwargs): res = func(*args, **kwargs) print(f"执行结果为: {res}") return res return inner @mylog def add(a, b): """ 功能: 实现加法运算 :param a: :param b: :return: """ return a + b # 打印函数的属性 print(f"add函数的名字: {add.__name__}") print(f"add函数的注释信息: {add.__doc__}") add(1, 2)
执行结果:
add函数的名字: add add函数的注释信息: 功能: 实现加法运算 :param a: :param b: :return: 执行结果为: 3
实现功能:
实现一个可以设置日志等级的log装饰器
思路分析:
为了让装饰器能够传参, 需要再嵌套一层函数
实现代码:
# -*- coding: utf-8 -*- from functools import wraps # 装饰器 def mylog(level="INFO"): def outter(func): @wraps(func) def inner(*args, **kwargs): res = func(*args, **kwargs) print(f"[{level}]函数{func.__name__}的执行结果为: {res}") return res return inner return outter @mylog(level="INFO") def add(a, b): return a + b @mylog(level="ERROR") def sub(a, b): return a - b # 打印函数的属性 add(1, 2) sub(1, 2)
执行结果:
[INFO]函数add的执行结果为: 3
[ERROR]函数sub的执行结果为: -1
# -*- coding: utf-8 -*- from functools import wraps # 装饰器1 def mylog1(func): @wraps(func) def inner(*args, **kwargs): res = func(*args, **kwargs) print(f"执行结果为: {res}") return res return inner # 装饰器2 def mylog2(level="INFO"): def outter(func): @wraps(func) def inner(*args, **kwargs): res = func(*args, **kwargs) print(f"[{level}]函数{func.__name__}的执行结果为: {res}") return res return inner return outter @mylog2(level="DEBUG") @mylog1 def add(a, b): return a + b # 多个装饰器的执行顺序: 从近到远依次执行 add(1, 2)
使用函数调用方式调用装饰器
mylog2(level="ERROR")(mylog1(add))(1, 2)
1. 装饰器可以在不改变原函数代码,不改变原函数调用方式的情况下, 给函数添加扩展功能
2. 装饰器的本质就是一个嵌套函数, 如果装饰器需要接收参数, 则需要增加一层函数嵌套
3. 装饰器有两种调用方式: 1函数传参方式, 2使用@语法糖
4. 装饰器的外层函数接收的是被装饰函数, 返回的是内层函数
5. 装饰器的内层函数(即闭包函数)负责装饰被装饰函数
6. 装饰器的常用场景有: 打印日志, 性能测试, 权限验证等
原文:https://www.cnblogs.com/reconova-56/p/15148637.html