python核心编程——装饰器

Posted tom-blogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python核心编程——装饰器相关的知识,希望对你有一定的参考价值。

定义两个功能函数:

技术图片
# -*- coding:utf-8 -*-


def foo():  # 打印"foo..."
    print("foo...")
    

def bar():  # 打印"bar..."
    print("bar...")
    
    
foo()  # foo...
bar()  # bar...
View Code

计算函数的运行时间,我们可以把函数改写为:

技术图片
import time  # 放在(文档)最顶端


def foo():
    start = time.time()  # 函数运行之前的时刻
    
    print("foo...")
    time.sleep(1)  # 因为该程序运行时间太短,所以运用time.sleep()延长1s时间
    
    end = time.time()  # 函数运行完后的时刻
    print(end - start)  # 打印运行的时间
    
    
def bar():
    start = time.time()  # 函数运行之前的时刻
    
    print("bar...")
    time.sleep(1)  # 因为该程序运行时间太短,所以运用time.sleep()延长1s时间
    
    end = time.time()  # 函数运行完后的时刻
    print(end - start)  # 打印运行的时间
    
    
foo()
# foo...
# 1.0006506443023682

bar()
# bar...
# 1.0007519721984863
View Code

通过在每个功能函数内部添加一些计算时间的代码,就能实现我们的需求,但是又出现了以下问题:

  1、修改了功能函数本身(每次调用函数,都会打印运行的时间,如果有的时候,我不想打印呢?)。

  2、代码量大,且重复(此处只有2个功能函数,我们可手动修改,如果有几十个,几百个,那岂不是要改到天手抽筋)。

 

所以,针对以上两点情况,及解决代码重复不修改函数本身,我们可以新定义一个计算时间的函数:

技术图片
import time


def foo():   # 打印"foo..."
    print("foo...")
    

def bar():  # 打印"bar..."
    print("bar...")
    
    
def caltime(func):  # 计算函数运行的时间
    start = time.time()  # 函数运行之前的时刻
    
    func()
    time.sleep(1)  # 因为该程序运行时间太短,所以运用time.sleep()延长1s时间
    
    end = time.time()  # 函数运行完后的时刻
    print(end - start)
    
    
caltime(foo)
# foo...
# 1.0009233951568604

caltime(bar)
# bar...
# 1.0008749961853027
View Code

我们发现,通过新建一个函数来实现一个功能,很方便、简洁。但是这样,函数的调用方式却发生了改变,比如:

我们最开始调用功能函数是:foo() 。现在要计算函数运行时间,我们的调用方式是:caltime(foo)

我们需要达到的需求是:就最终执行foo(),就可实现该函数本身的功能计算该函数运行的时间。而不是caltime(foo)。

 

如果我们的项目中调用了几十次foo函数,并且都需要计算时间,那我们岂不是也要挨个把foo()改成caltime(foo) ,其实这也是一件恼火的事情。所以我们得像个办法(就是还是书写foo()调用函数,但是同时可以计算运行的时间):

技术图片
import time


def foo():   # 打印"foo..."
    print("foo...")
    

def bar():  # 打印"bar..."
    print("bar...")


def caltime(func):
    def inner():
        start = time.time()
    
        func()
        time.sleep(1)
    
        end = time.time()
        print(end - start)
    
    return inner


foo = caltime(foo)
foo()
# foo...
# 1.0006935596466064
View Code

最后我们就是通过foo()而不是caltime(foo)来调用函数的。所以,我们就可通过把函数当作返回值传递,来实现最终的调用方式(调用函数时的书写方式)相同。

caltime(foo)的执行结果是,返回的inner函数(并不会执行inner函数),然后把这个inner函数赋值给foo(即foo=caltime(foo))。所以,foo()就相当于在执行inner()。

这里的caltime()就是装饰器,但是我们会发现,每次执行foo()之前,都会写上foo=caltime(foo),也挺麻烦的,所以装饰器更专业更优雅写法就是:

  1、把装饰器caltime()写在功能函数前面;

  2、把foo=caltime(foo)这句每次调用都会写(重复)的代码写成 @caltime 的方式,放到功能函数前面。

技术图片
import time


def caltime(func):
    def inner():
        start = time.time()
    
        func()
        time.sleep(1)
    
        end = time.time()
        print(end - start)
    
    return inner


@caltime  # 此时caltime就相当于是foo=caltime(foo)
def foo():   # 打印"foo..."
    print("foo...")
    

def bar():  # 打印"bar..."
    print("bar...")


# foo = caltime(foo)
foo()
# foo...
# 1.000216007232666
View Code

 

以上是关于python核心编程——装饰器的主要内容,如果未能解决你的问题,请参考以下文章

python核心编程——装饰器

Python核心编程的四大神兽:迭代器生成器闭包以及装饰器

面向对象编程思想 以及 封装,继承,多态 和 python中实例方法,类方法,静态方法 以及 装饰器

Python核心编程的四大神兽

python装饰器了解

python 装饰器