Python: 装饰器和语法糖

一、Python 装饰器

Python 装饰器本身就是一个函数,它的作用是装饰一个其他的函数,但是不改变原有的程序功能,还要增添新的功能,调用函数时的接口没有变化。比如,装修一个房子,如果不隔音,我在墙上加一层隔音板,却不能把墙拆了,换成隔音材质。

import time   #导入时间模块

def index():
    time.sleep(2)    #时间休眠2秒

start_time = time.time()  #time.time 是时间戳,指北京时间19700101 080000 起至现在的总毫秒数
index()
end_time = time.time()
print(end_time - start_time)    #2.0136349201202393

虽然完成了计时功能,但如果函数有非常多个,那每一个函数的计时都要定义开始时间和结束时间的变量,比较繁琐。

import time   #导入时间模块

def index():
    time.sleep(2)    #时间休眠2秒

def calculate_time(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print(end_time - start_time)
calculate_time(index)            #2.0035324096679688

但装饰器不改变原有的函数调用接口,之前的函数是index 而现在要写上calculate_time(index),这样也是很不方便的。比如玩家在玩游戏时通常用WASD来控制上下左右,有一天如果改成了CSAV来控制,肯定就会有很多玩家放弃这个游戏,因此我们需要进一步升级程序。

import time   #导入时间模块

def index():
    time.sleep(2)    #时间休眠2秒

def calculate_time(f):
    def inner():
         start_time = time.time()
         f()
         end_time = time.time()
         print(end_time - start_time)
    return inner
index = calculate_time(index)
index()         #2.0142064094543457

这样,既可以不改变接口又可以成功运行程序。

二、语法糖

在用装饰器之前还要写上 index = calculate_time(index) 这样一行代码,显然是很不方便的。这时候可以用 @calculate_time 替换 index = calculate_time(index)

import time   #导入时间模块

def calculate_time(f):
    def inner():
         start_time = time.time()
         f()
         end_time = time.time()
         print(end_time - start_time)
    return inner

@calculate_time      # 等价于index = calculate_time(index) 这行赋值的代码
def index():
    time.sleep(2.2)    #时间休眠2.2秒

index()         #2.2051877975463867

举例

import time

def timer(func):
    '''统计函数运行时间的装饰器'''
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        used = end - start
        print(f'{func.__name__}used{used}')
    return wrapper
@timer
def step1():
    print('step1.....')

@timer
def step2():
    print('step2.....')

@timer
def step3():
    print('step3.....')
step1()
step2()
step3()

你可能感兴趣的