1. 程式人生 > >[python]利用裝飾接受引數,來統計函式執行是否超過了設定的秒數,並可以隨時修改裝飾器的引數

[python]利用裝飾接受引數,來統計函式執行是否超過了設定的秒數,並可以隨時修改裝飾器的引數

#利用裝飾接受引數,來統計函式執行是否超過了設定的秒數,並可以隨時修改裝飾器的引數


import time
import logging

def warn_timeout(timeout):
    def decorator(func):
        def wrap(*args, **kwargs):
            t0 = time.time()
            res = func(*args, **kwargs)
            used = time.time() - t0
            if used > timeout:
                logging.warning('%s: %s > %s', func.__name__, used, timeout)
            return res
        def set_timeout(new_timeout):
            nonlocal timeout    # nonlocal改變 變數的引用的值,只能在python3用
            #nonlocal關鍵字用來在函式或其他作用域中使用外層(非全域性)變數
            timeout = new_timeout   # 把新值傳給timeout
        wrap.set_timeout = set_timeout  #這裡,函式也是可以定義變數的。這個變數就是個函式
        return wrap
    return decorator

import random
@warn_timeout(1.5)
def f(i):
    print('in f [%s]' % i)
    while random.randint(0, 1): # 這裡也非常優秀相當於 50%的機率
        time.sleep(0.6)

for i in range(20):
    f(i)

f.set_timeout(1)   # 函式的變數相當於調了函式,改變了引數的值

for i in range(20):
    f(i)

#在python2中沒有nonlocal這個,可以利用列表是可變屬性,來實行更改值

import time
import logging

def warn_timeout(timeout):
    def decorator(func):
        _timeout = [timeout] #在這先弄一個列表
        def wrap(*args, **kwargs):
            timeout = _timeout[0]   #每次調取的列表的第0個值,
            t0 = time.time()
            res = func(*args, **kwargs)
            used = time.time() - t0
            if used > timeout:
                logging.warning('%s: %s > %s', func.__name__, used, timeout)
            return res
        def set_timeout(new_timeout):
            #nonlocal timeout
            #timeout = new_timeout
            _timeout[0] = new_timeout #改變的話,就改變列表的第0個值
        wrap.set_timeout = set_timeout
        return wrap
    return decorator

import random
@warn_timeout(1.5)
def f(i):
    print('in f [%s]' % i)
    while random.randint(0, 1):
        time.sleep(0.6)

for i in range(30):
    f(i)

f.set_timeout(1)
for i in range(30):
    f(i)