在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Python裝飾器如何增加任務(wù)超時退出功能

科技綠洲 ? 來源:Python實用寶典 ? 作者:Python實用寶典 ? 2023-11-01 10:53 ? 次閱讀

任務(wù)超時退出

我們?nèi)粘T谑褂玫母鞣N網(wǎng)絡(luò)請求庫時都帶有timeout參數(shù),例如request庫。這個參數(shù)可以使請求超時就不再繼續(xù)了,直接拋出超時錯誤,避免等太久。

如果我們自己開發(fā)的方法也希望增加這個功能,該如何做呢?

方法很多,但最簡單直接的是使用并發(fā)庫futures,為了使用方便,我將其封裝成了一個裝飾器,代碼如下:

import functools
from concurrent import futures

executor = futures.ThreadPoolExecutor(1)

def timeout(seconds):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            future = executor.submit(func, *args, **kw)
            return future.result(timeout=seconds)
        return wrapper
    return decorator

定義了以上函數(shù),我們就有了一個超時結(jié)束的裝飾器,下面可以測試一下:

import time

@timeout(1)
def task(a, b):
    time.sleep(1.2)
    return a+b

task(2, 3)

結(jié)果:

---------------------------------------------------------------------------
TimeoutError                              Traceback (most recent call last)
...
D:Anaconda3libconcurrentfutures_base.py in result(self, timeout)
    432                 return self.__get_result()
    433             else:
-- > 434                 raise TimeoutError()
    435 
    436     def exception(self, timeout=None):

TimeoutError:

上面我們通過裝飾器定義了函數(shù)的超時時間為1秒,通過睡眠模擬函數(shù)執(zhí)行超過1秒時,成功的拋出了超時異常。

程序能夠在超時時間內(nèi)完成時:

@timeout(1)
def task(a, b):
    time.sleep(0.9)
    return a+b

task(2, 3)

結(jié)果:

5

可以看到,順利的得到了結(jié)果。

這樣我們就可以通過一個裝飾器給任何函數(shù)增加超時時間,這個函數(shù)在規(guī)定時間內(nèi)還處理不完就可以直接結(jié)束任務(wù)。

前面我將這個裝飾器將所需的變量定義到了外部,其實我們還可以通過類裝飾器進一步封裝,代碼如下:

import functools
from concurrent import futures

class timeout:
    __executor = futures.ThreadPoolExecutor(1)

    def __init__(self, seconds):
        self.seconds = seconds

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            future = timeout.__executor.submit(func, *args, **kw)
            return future.result(timeout=self.seconds)
        return wrapper

經(jīng)測試使用類裝飾器能得到同樣的效果。

注意:使用@functools.wraps的目的是因為被裝飾的func函數(shù)元信息會被替換為wrapper函數(shù)的元信息,而@functools.wraps(func)將wrapper函數(shù)的元信息替換為func函數(shù)的元信息。最終雖然返回的是wrapper函數(shù),元信息卻依然是原有的func函數(shù)。

在函數(shù)式編程中,函數(shù)的返回值是函數(shù)對象被稱為閉包。

日志記錄

如果我們需要記錄部分函數(shù)的執(zhí)行時間,函數(shù)執(zhí)行前后打印一些日志,裝飾器是一種很方便的選擇。

代碼如下:

import time
import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        res = func(*args, **kwargs)
        end = time.perf_counter()
        print(f'函數(shù) {func.__name__} 耗時 {(end - start) * 1000} ms')
        return res
    return wrapper

裝飾器 log 記錄某個函數(shù)的運行時間,并返回其執(zhí)行結(jié)果。

測試一下:

@log
def now():
    print('2021-7-1')

now()

結(jié)果:

2021-7-1
函數(shù) now 耗時 0.09933599994838005 ms

緩存

如果經(jīng)常調(diào)用一個函數(shù),而且參數(shù)經(jīng)常會產(chǎn)生重復(fù),如果把結(jié)果緩存起來,下次調(diào)用同樣參數(shù)時就會節(jié)省處理時間。

定義函數(shù):

import math
import random
import time


def task(x):
    time.sleep(0.01)
    return round(math.log(x**3 / 15), 4)

執(zhí)行:

%%time
for i in range(500):
    task(random.randrange(5, 10))

結(jié)果:

Wall time: 5.01 s

此時如果我們使用緩存的效果就會大不一樣,實現(xiàn)緩存的裝飾器有很多,我就不重復(fù)造輪子了,這里使用functools包下的LRU緩存:

from functools import lru_cache

@lru_cache()
def task(x):
    time.sleep(0.01)
    return round(math.log(x**3 / 15), 4)

執(zhí)行:

%%time
for i in range(500):
    task(random.randrange(5, 10))

結(jié)果:

Wall time: 50 ms

約束某個函數(shù)的可執(zhí)行次數(shù)

如果我們希望程序中的某個函數(shù)在整個程序的生命周期中只執(zhí)行一次或N次,可以寫一個這樣的裝飾器:

import functools


class allow_count:
    def __init__(self, count):
        self.count = count
        self.i = 0

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            if self.i >= self.count:
                return
            self.i += 1
            return func(*args, **kw)
        return wrapper

測試:

@allow_count(3)
def job(x):
    x += 1
    return x


for i in range(5):
    print(job(i))

結(jié)果:

1
2
3
None
None
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 參數(shù)
    +關(guān)注

    關(guān)注

    11

    文章

    1839

    瀏覽量

    32295
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4801

    瀏覽量

    68735
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4799

    瀏覽量

    84810
收藏 人收藏

    評論

    相關(guān)推薦

    python學(xué)習(xí):三個測試庫的裝飾實現(xiàn)思路

    Python 中實現(xiàn)參數(shù)化測試的幾個庫,并留下一個問題: 它們是如何做到把一個方法變成多個方法,并且將每個方法與相應(yīng)的參數(shù)綁定起來的呢? 我們再提煉一下,原問題等于是:在一個類中,如何使用裝飾
    的頭像 發(fā)表于 09-27 11:44 ?3187次閱讀
    <b class='flag-5'>python</b>學(xué)習(xí):三個測試庫的<b class='flag-5'>裝飾</b><b class='flag-5'>器</b>實現(xiàn)思路

    理解Python裝飾及其工作原理

    Python 是一種對新手很友好的語言。但是,它也有很多較難掌握的高級功能,比如裝飾(decorator)。很多初學(xué)者一直不理解裝飾
    發(fā)表于 10-08 11:39 ?2236次閱讀

    分享python 7個好用的裝飾

    ): return x + y4、deprecated這個相信大家在使用別的包時都遇到過,當(dāng)要下線一個老版本的函數(shù)的時候就可以使用這個裝飾。安裝:pip install Deprecated
    發(fā)表于 06-15 16:54

    如何實現(xiàn)事件結(jié)構(gòu)中存在多個超時功能

    實現(xiàn)事件結(jié)構(gòu)中存在多個超時功能
    發(fā)表于 04-03 14:57 ?2次下載

    一文讀懂Python裝飾

    裝飾前,還要先要明白一件事,Python 中的函數(shù)和 Java、C++不太一樣,Python 中的函數(shù)可以像普通變量一樣當(dāng)做參數(shù)傳遞給另外一個函數(shù)。
    發(fā)表于 04-28 10:48 ?3430次閱讀
    一文讀懂<b class='flag-5'>Python</b><b class='flag-5'>裝飾</b><b class='flag-5'>器</b>

    讓你學(xué)寫Python裝飾的五大理由

    你必須學(xué)寫Python裝飾的五個理由
    的頭像 發(fā)表于 03-02 10:06 ?1918次閱讀

    Python的函數(shù)裝飾器使用方法

    Python中的裝飾是一種可以裝飾其它對象的工具,簡單地說,他們是修改其他函數(shù)的功能的函數(shù)。該工具本質(zhì)上是一個可調(diào)用的對象(callabl
    的頭像 發(fā)表于 01-21 11:36 ?1593次閱讀
    <b class='flag-5'>Python</b>的函數(shù)<b class='flag-5'>裝飾</b>器使用方法

    Python裝飾的原理和案例

    Python中的裝飾器用于擴展可調(diào)用對象的功能,而無需修改其結(jié)構(gòu)。基本上,裝飾函數(shù)包裝另一個函數(shù)以增強或修改其行為。我們可以通過一個具體的
    的頭像 發(fā)表于 07-01 11:35 ?2252次閱讀

    Python定時任務(wù)的實現(xiàn)方式

    在日常工作中,我們常常會用到需要周期性執(zhí)行的任務(wù),一種方式是采用 Linux 系統(tǒng)自帶的 crond 結(jié)合命令行實現(xiàn)。另外一種方式是直接使用Python。接下來整理的是常見的Python定時
    的頭像 發(fā)表于 10-08 15:20 ?5756次閱讀

    Python裝飾的使用

    定義 首先我們先來了解下裝飾的定義。顧名思義,在Python中,裝飾本質(zhì)上就是一個函數(shù),它可以接收一個函數(shù)作為參數(shù),然后返回一個新的函數(shù)
    的頭像 發(fā)表于 06-21 16:54 ?758次閱讀

    裝飾模式和代理模式的區(qū)別

    什么是裝飾模式 裝飾模式(Decorator Pattern): 在不改變對象自身的基礎(chǔ)上,在程序運行期間給對象動態(tài)的添加職責(zé); 感覺和繼承如出一轍,不改變父類,子類可拓展
    的頭像 發(fā)表于 10-08 14:25 ?3932次閱讀
    <b class='flag-5'>裝飾</b><b class='flag-5'>器</b>模式和代理模式的區(qū)別

    Python自制簡單實用的日志裝飾

    在寫代碼的時候,往往會漏掉日志這個關(guān)鍵因素,導(dǎo)致功能在使用的時候出錯卻無法溯源。 其實,只需要寫一個非常簡單的日志裝飾,我們就能大大提升排查問題的效率。 1.簡陋版裝飾
    的頭像 發(fā)表于 10-21 14:39 ?739次閱讀
    <b class='flag-5'>Python</b>自制簡單實用的日志<b class='flag-5'>裝飾</b><b class='flag-5'>器</b>

    Python 自制簡單實用的日志裝飾

    在寫代碼的時候,往往會漏掉日志這個關(guān)鍵因素,導(dǎo)致功能在使用的時候出錯卻無法溯源。 其實,只需要寫一個非常簡單的日志裝飾,我們就能大大提升排查問題的效率。 1.簡陋版裝飾
    的頭像 發(fā)表于 10-31 15:05 ?502次閱讀
    <b class='flag-5'>Python</b> 自制簡單實用的日志<b class='flag-5'>裝飾</b><b class='flag-5'>器</b>

    如何寫一個簡單的裝飾

    今天介紹的是一個已經(jīng)存在十三年,但是依舊不紅的庫 decorator,好像很少有人知道他的存在一樣。 這個庫可以幫你做什么呢 ? 其實很簡單,就是可以幫你更方便地寫python裝飾代碼,更重
    的頭像 發(fā)表于 11-01 09:54 ?500次閱讀
    如何寫一個簡單的<b class='flag-5'>裝飾</b><b class='flag-5'>器</b>

    【每天學(xué)點AI】一個例子帶你了解Python裝飾到底在干嘛!

    今天我們來聊聊一種能給你的代碼變得“加料”的神器——Python裝飾。就像一杯咖啡,原本它是苦的,為了讓它符合我的口味,我給它添加了糖,添加之后就完美的符合了我的口味。那么,裝飾
    的頭像 發(fā)表于 09-20 16:54 ?566次閱讀
    【每天學(xué)點AI】一個例子帶你了解<b class='flag-5'>Python</b><b class='flag-5'>裝飾</b><b class='flag-5'>器</b>到底在干嘛!
    主站蜘蛛池模板: 午夜精品免费| 二级黄绝大片中国免费视频 | 国产在线观看午夜不卡| 奇米999| 国模久久| 日本理论午夜中文字幕第一页| 四虎影院最新网址| 四虎影像| 欧美成人综合在线| 色多多网站| 尤物啪啪| a欧美视频| 性欧美videofree视频另类| 四虎国产精品永久地址51| 全黄h全肉边做边吃奶在线观看| 五月激情婷婷网| 一级一级女人18毛片| 五月天婷婷在线视频| 你懂的福利| 欧美片欧美日韩国产综合片| 免费看污黄视频软件| 国产亚洲欧洲人人网| 香蕉操| 网色| 孩交啪啪网址| 黄色福利站| 中文字幕亚洲一区二区v@在线| 2018天天干夜夜操| 热99久久| 高h细节肉爽文男男| 毛片基地在线| 四虎影裤| 国产亚洲精品线观看77| 天天射天天舔| 日日操狠狠操| 免费免费啪视频在线| 黄色网络在线观看| 被cao到合不拢腿腐男男| 日本乱理论片免费看| 99在线国产视频| 成人在线一区二区三区|