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装饰器的主要内容,如果未能解决你的问题,请参考以下文章

[TimLinux] Python 装饰器

python装饰器

python装饰器关键代码

Python装饰器

python之装饰器

python 装饰器