Python装饰器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python装饰器相关的知识,希望对你有一定的参考价值。
法宝一:作用域
- L:local,局部作用域,即函数中定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
- G:globa,全局变量,就是模块级别定义的变量;
- B:built-in,系统固定模块里面的变量,比如int, bytearray等。
- 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
法宝二:高阶函数
法宝三:装饰器
(1).闭包
def outer(): x = 1 def inner(): print(x) # 1 对外部变量的引用 # inner() # 2 内部函数 return inner # outer() in_func = outer() #这里outer()复制的对象其实就是返回值 inner指向的对象,和a=1,b=2一样 in_func() #这里就是使用inner指向的对象
为什么in_func()可以执行函数内的inner()呢?还可以调用函数内的x?
因为inner是一个闭包函数
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
上面的inner()就是一个内部函数,x就是对外部变量的引用
(2).装饰器
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
对函数执行时间输出到日志中:
import time
def t1():
print(‘t1‘)
time.sleep(1)
def t2():
time.sleep(2)
def funk_time(f):
start_time=time.time()
f()
end_time=time.time()
print(end_time-start_time)
logger()
funk_time(t1)
逻辑上不难理解,而且运行正常。 但是这样的话,你基础平台的函数修改了名字,容易被业务线的人投诉的,因为我们每次都要将一个函数作为参数传递给show_time函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行运行foo(),但是现在不得不改成show_time(foo)。那么有没有更好的方式的呢?当然有,答案就是装饰器。
改进一
import time def t1(): print(‘t1‘) time.sleep(1) def t2(): time.sleep(2) def funk_time(f): def inner(): #1内部函数 start_time=time.time() f() #2调用外部变量 end_time=time.time() print(end_time-start_time) #logger() return inner()
t1=funk_time(t1) t1()
我们看到了,如果计算一个函数的运行时间就要赋值一次,比较麻烦,这里我们引用@符号的方法
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
改进2
import time
def funk_time(f):
def inner(): #1内部函数
start_time=time.time()
f() #2调用外部变量
end_time=time.time()
print(end_time-start_time)
#logger()
return inner
@funk_time #等于 t1=funk_time(t1)
def t1():
print(‘t1‘)
time.sleep(1)
@funk_time
def t2():
print(‘t2‘)
time.sleep(2)
t1()
这里需要注意的问题: t1=funk_time(t1)其实是把inner引用的对象引用给了t1,而inner里的变量f之所以可以用,就是因为inner是一个闭包函数。
带参数的被装饰函数:
import time def funk_time(f): def inner(x,y): #1内部函数 start_time=time.time() f(x,y) #2调用外部变量 end_time=time.time() print(end_time-start_time) #logger() return inner @funk_time def t1(a,b): print(a+b) time.sleep(1) t1(1,2)
###########不定长参数
import time def funk_time(f): def inner(*x,**y): #1内部函数 start_time=time.time() f(*x,**y) #2调用外部变量 end_time=time.time() print(end_time-start_time) #logger() return inner @funk_time def t1(*a,**b): print(a) print(b) time.sleep(1) t1(1,23,4,5) #(1, 23, 4, 5) #{} #1.0003044605255127
带参数的装饰器
import time def time_logger(flag=0): def funk_time(f): def inner(*x,**y): #1内部函数 start_time=time.time() f(*x,**y) #2调用外部变量 end_time=time.time() print(end_time-start_time) if flag: print(‘记录到日志‘) #logger() return inner return funk_time
@time_logger(2) #根据这儿的参数决定加到日志中不要 def t1(*a,**b): print(a) print(b) time.sleep(1) t1(1,2,3,4)
#(1, 2, 3, 4)
#{}
#1.0002663135528564
#记录到日志
以上是关于Python装饰器的主要内容,如果未能解决你的问题,请参考以下文章