1. 程式人生 > >Python3學習筆記(十三):裝飾器

Python3學習筆記(十三):裝飾器

nbsp lee 一個 col false UNC for strong 直接

裝飾器就是一個閉包,它的主要作用是在不改變原函數的基礎上對原函數功能進行擴展。

我們先來寫一個簡單的函數:

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)

Python3學習筆記(十三):裝飾器