Believe in yourself.

Python3学习笔记(十三):装饰器

装饰器就是一个闭包,它的主要作用是在不改变原函数的基础上对原函数功能进行扩展。

我们先来写一个简单的函数:

from time import sleep


def foo():
    print("Hello World!")
    sleep(2)

现在我们要对这个函数加一些功能,比如说打印这个函数的执行时间

有人说,这还不简单啊,直接修改foo函数呢,确实,这是最简单的一种方法。但是在我们实际工作中,有时候是不能对调用的函数进行修改的,那该怎么办呢?

我们可以重新写个打印时间的函数去调用foo函数啊,比如:

import time
from time import sleep

def foo():
    print("Hello World!")
    sleep(2)

def show_time(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(end_time - start_time)

调用:

show_time(foo)

# 输出:
Hello World!
2.0000178813934326

很好,确实是在不修改foo函数的基础上实现了需求,但是。。。。。有个大问题,改变了函数的调用方式,前面是调用foo()的,现在需要修改成调用show_time()。

看来这种方法也不行。

这个时候就是闭包大展身手的机会了

import time
from time import sleep

def foo():
    print("Hello World!")
    sleep(2)

def show_time(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time - start_time)
    return inner

#  调用
foo = show_time(foo)
foo()

# 输出
Hello World!
2.000027656555176

到这里已经完美地实现了我们的需求,这就是装饰器。装饰器有个高大上的写法,就是装饰器符号@

上面的代码我们修改成用装饰器符号@来写:

import time
from time import sleep

def show_time(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time - start_time)
    return inner

@show_time    # 其实就相当于foo = show_time(foo)
def foo():
    print("Hello World!")
    sleep(2)

# 调用
foo()

@show_time的作用就是执行foo()时,跳转到去执行inner(),如下图:

被装饰函数的参数

如果被装饰的函数有形参,那么在装饰器函数中该怎么写呢?

import time
from time import sleep


def show_time(func):
    def inner(*x):
        start_time = time.time()
        func(*x)
        end_time = time.time()
        print(end_time - start_time)
    return inner


@show_time
def add(*args):
    sum = 0
    for arg in args:
        sum += arg
    print(sum)
    sleep(2)


add(3, 5)

装饰器函数参数

有些时候我们可能需要对不同的被装饰函数加些不同的功能,比如需要对某些函数加上日志打印,那该怎么做呢?

import time
from time import sleep


def logger(flag="false"):
    def show_time(func):
        def inner(*x):
            start_time = time.time()
            func(*x)
            end_time = time.time()
            print(end_time - start_time)
            if flag == "true":
                print("打印日志记录")
        return inner
    return show_time


@logger("true")   # 打印日志记录
def add(*args):
    sum = 0
    for arg in args:
        sum += arg
    print(sum)
    sleep(2)

@logger()   # 不需要打印日志记录
def foo():
    print("Hello World!")
    sleep(2)

 

posted @ 2018-06-03 18:23  eastonliu  阅读(260)  评论(0编辑  收藏  举报