1. 程式人生 > >python 64式: 第5式、裝飾器

python 64式: 第5式、裝飾器


#!/usr/bin/env python
# -*- coding: utf-8 -*-

from datetime import datetime
import functools
import time

'''
關鍵:
1 裝飾器
含義:程式碼執行期間動態增加功能
本質:返回函式的高階函式,接收函式本身作為引數,返回一個包含對該函式前後處理的函式

2 無參裝飾器: 
def timeHelper(func):
    def wrapper(*args, **kwargs):
        ...
	func(*args, **kwargs)
	...
    return wrapper

@timeHelper
def run():
    ...
等同於
run = timeHelper(run)

3 有參裝飾器:
如果裝飾器本身需要傳入引數,需要定義三層函式
最外層函式的引數是裝飾器本身引數,中間函式的引數是函式物件,
最裡面函式的引數是*args,**kwargs
def timeHelperWithParam(text):
    def _wrapper(func):
        def wrapper(*args, **kwargs):
	    ...
	    func(*args, **kwargs)
	    ...
        return wrapper
    return _wrapper

@timeHelperWithParam('function name')
def run():
    ...
等同於
run = timeHelperWithParam('function name')(run)
解釋:
timeHelperWithParam('function name')是一個函式類

4 保持函式名稱不隨裝飾器改變
只需要新增:  @functools.wraps(func)
具體用法如下:
def timeHelperWithParam(text):
    @functools.wraps(func)
    def _wrapper(func):
        def wrapper(*args, **kwargs):
	    ...
	    func(*args, **kwargs)
	    ...
        return wrapper
    return _wrapper

參考:
https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819879946007bbf6ad052463ab18034f0254bf355000
'''

def timeHelper(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            start = datetime.now()
            info = "############ Function name: %s, Starts at: %s ##########" % (
                func.__name__, str(start))
            print info
            func(*args, **kwargs)
            end = datetime.now()
            diff = end - start
            info = "############ Function name: %s, Ends at: %s, cost time: %s ############ " % (
                func.__name__, str(end), str(diff))
            print info
        except Exception as ex:
            info = "Exception type is %s, message is %s" % (ex.__class__.__name__, ex)
            print info
    return wrapper


@timeHelper
def run():
    time.sleep(3)


def timeHelperWithParam(text):
    def _wrapper(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                start = datetime.now()
                info = "############ Function name: %s, Text: %s, Starts at: %s ##########" % (
                    func.__name__, text, str(start))
                print info
                func(*args, **kwargs)
                end = datetime.now()
                diff = end - start
                info = "############ Function name: %s, Text: %s, Ends at: %s, cost time: %s ############ " % (
                    func.__name__, text, str(end), str(diff))
                print info
            except Exception as ex:
                info = "Exception type is %s, message is %s" % (ex.__class__.__name__, ex)
                print info
        return wrapper
    return _wrapper


@timeHelperWithParam('run function')
def runWithParam():
    time.sleep(3)

def process():
    run()
    runWithParam()
    newRun = timeHelper(run)
    print newRun.__name__


if __name__ == "__main__":
    process()