一装饰器前戏 - 闭包
简单来说, python 中函数的闭包就是在内部函数里对外部作用域 (但不是全局作用域) 的变量进行引用, 这么说, 不太好理解, 下面的示例帮助理解
- def outer():
- a = 1
- def inner(): # 内部函数 inner
- print(a) # 调用外部环境变量
- return inner
- f = outer()
- f()
上面的示例就是一个闭包, inner 是个内部函数, inner 里调用外部作用域变量 a,a 不是全局变量; 这样构成了一个闭包上面这个例子外部变量是给定的, 那么我们通过传参来给定外部变量
- def outer(a):
- def inner(): # 内部函数 inner
- print(a) # 调用传入的外部环境变量
- return inner
- f = outer(10)
- f()
二装饰器
装饰器也是函数, 它实现的功能是在不改动原有函数代码的条件下, 添加新的功能, 装饰器的返回值也是函数对象
先来看一个简单的例子
- def fun1():
- print("111222333")
这是甲写的一个函数, 我们要记录执行函数的日志
- def fun1():
- print("111222333")
- logging.info("Program is running")
如上, 我们导入了 logging 模块, 在 fun1 函数中加入日志记录, 简单实现了功能, 但是如果这样需要记录日志的函数有很多个, 我们在一个个的加的话, 就会有大量的重复, 这种情况下, 我们就需要使用装饰器, 来抽离出与函数功能无关的重复代码
下面是一个简单的装饰器:
- import logging
- def outer(f):
- def inner():
- f()
- logging.warn("Program is running")
- return inner
- def fun1():
- print("111222333")
- fun1 = outer(fun1)
- fun1()
函数 outer 就是一个装饰器函数, 他把 fun1 包裹起来, 但是 fun1 = outer(fun1), 这句需要在每一个需要被装饰的函数下重新赋值, 这个怎们办呢, 可以用装饰器特有的语法来解决
- import logging
- def outer(f):
- def inner():
- f()
- logging.warn("Program is running")
- return inner
- @outer
- def fun1():
- print("111222333")
- @outer
- def fun2():
- print("444555666")
- fun1()
- fun2()
三带参数的装饰器
上面的例子中, 被装饰的函数不带参数, 实际上更多情况下函数需要参数, 我们来修改一下
- import logging
- def outer(f):
- def inner(*args,**kwargs):
- f(*args,**kwargs)
- logging.warn("Program is running")
- return inner
- @outer
- def fun1(*args,**kwargs):
- print(args)
- fun1(1,2,3,4,5)
上面的例子使被装饰的函数带上了参数, 其实, 装饰器还有更大的灵活性, 装饰器本身也可以带参数传递
- import logging
- def outer(log_level):
- def decorator(f):
- def inner(*args,**kwargs):
- f(*args,**kwargs)
- if log_level == "warn":
- logging.warn("Program is running")
- return inner
- return decorator
- @outer(log_level="warn")
- def fun1(*args,**kwargs):
- print(args)
- fun1(1,2,3,4,5)
来源: http://www.bubuko.com/infodetail-2510974.html