如何以比較優(yōu)雅的方式為python-while增加超時(shí)猾警?

遇到的問題:

在日常編碼過程,可能會(huì)遇到這種場(chǎng)景:需要較多次嘗試獲取數(shù)據(jù)隆敢,你寫的程序不知道何時(shí)能拿到數(shù)據(jù)发皿,于是通過for或者while去“詢問”,如以下的偽代碼示意:

def get_data_from_remote():
      return data

while True:
      data = get_data_from_remote()
      if data:
          break

這段代碼拂蝎,只要沒有獲取到數(shù)據(jù)穴墅,就會(huì)一直循環(huán)執(zhí)行,主線程一直處于阻塞狀態(tài)匣屡,也就是我們常說的“死循環(huán)”封救。那么我們?cè)趺唇鉀Q這一問題呢?

幾種方案:

如果作為初級(jí)玩家捣作,每次遇到這種場(chǎng)景誉结,都寫以下一段邏輯:

start_time = datetime.datetime.now()
timeout = 5
while True:
      data = get_data_from_remote()
      if data:
          break
      if (datetime.datetime.now() -start_time).seconds> timeout:
            raise TimeoutException

不錯(cuò)效果達(dá)到了,但不具有通用性券躁,當(dāng)然小編想不到更低級(jí)的寫法了惩坑。所以思考一下,怎么更具通用性也拜?
如果 while關(guān)鍵字能自帶超時(shí)效果就好了撒桨,以小編淺薄的知識(shí)面搬俊,想到了兩種方式:

  • python解釋器
    修改python解釋器,把while這個(gè)關(guān)鍵字功能豐富一下(雖然C語言是最好的語言,但我的這塊知識(shí)都全部還給大學(xué)老師了)
  • ast
    通過ast(抽象語法樹)這個(gè)底層庫履肃,通過代碼替換的方式,這種方式小編幾年前用過抛虫,比如把time.sleep(1000) 悄悄地改成sleep(1)懂缕,再例如python著名測(cè)試框架pytest就是用這種方式把a(bǔ)ssert關(guān)鍵字給重寫了。

然而這兩種方式都要較深的功力键俱,第2種方式可以做出來兰绣,但實(shí)現(xiàn)成本也不低,性能也不會(huì)太高编振。

  • 方式3
    于是思考有沒有更簡(jiǎn)單的方式缀辩,想到可以“自動(dòng)”修改while的條件, 請(qǐng)看下面的代碼:
# self_while.py
import datetime
import sys
import traceback
from contextlib import contextmanager


class Condition(object):
    def __init__(self, cond_str, timeout):
        self.start = datetime.datetime.now()
        self.cond_str = cond_str
        self.timeout = timeout

    def __call__(self, *args, **kwargs):
        frame = sys._getframe(1)
        c = eval(self.cond_str, frame.f_locals)
        return (datetime.datetime.now() - self.start).seconds < self.timeout and c


@contextmanager
def ext_while_cond(whl_cond, timeout=5):
    cond_str = get_cond_str()
    cond = Condition(cond_str, timeout)
    yield cond


whl_line_ = 'with ' + ext_while_cond.__name__ + '('


def get_cond_str():
    x = traceback.extract_stack()
    for i in range(len(x)):
        code_line = x[i].line
        if whl_line_ in code_line:
            break
    if whl_line_ not in code_line:
        raise Exception('Cannot Find While Statement')
    else:
        l_idx, r_idx = code_line.find("("), code_line.rfind(")")
        return code_line[l_idx + 1, r_idx]

使用這些代碼的例子:

import time

from self_while import ext_while_cond


def test1():
    flag = True
    with ext_while_cond(flag is True) as cond:
        while cond():
            # flag = False
            time.sleep(1)
            print("A")


def test2():
    flag1 = True
    flag2 = False
    with ext_while_cond((flag1 and not flag2), timeout=2) as cond:
        while cond():
            time.sleep(1)
            print("A")


if __name__ == '__main__':
    test1()

可以看出,調(diào)用的地方比之前就多一行代碼:with ext_while_cond((flag1 and not flag2), timeout=2) as cond踪央。
self_while里面的代碼臀玄,使用了反射、作用域杯瞻、上下文管理裝飾器等知識(shí)镐牺,可以細(xì)品一下,全展開說太累了魁莉。

這個(gè)工具類沒有實(shí)現(xiàn)超時(shí)后睬涧,拋一個(gè)超時(shí)異常出來募胃,讀者可以自己實(shí)現(xiàn)。
感謝閱讀畦浓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痹束,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子讶请,更是在濱河造成了極大的恐慌祷嘶,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺溢,死亡現(xiàn)場(chǎng)離奇詭異论巍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)风响,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門嘉汰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人状勤,你說我怎么就攤上這事鞋怀。” “怎么了持搜?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵密似,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我葫盼,道長(zhǎng)残腌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任贫导,我火速辦了婚禮废累,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脱盲。我一直安慰自己,他們只是感情好日缨,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布钱反。 她就那樣靜靜地躺著,像睡著了一般匣距。 火紅的嫁衣襯著肌膚如雪面哥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天毅待,我揣著相機(jī)與錄音尚卫,去河邊找鬼。 笑死尸红,一個(gè)胖子當(dāng)著我的面吹牛吱涉,可吹牛的內(nèi)容都是我干的刹泄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼怎爵,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼特石!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鳖链,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤姆蘸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后芙委,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逞敷,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年灌侣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了推捐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顶瞳,死狀恐怖玖姑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慨菱,我是刑警寧澤焰络,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站符喝,受9級(jí)特大地震影響闪彼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜协饲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一畏腕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茉稠,春花似錦描馅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至膀篮,卻和暖如春嘹狞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背誓竿。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國打工磅网, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筷屡。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓涧偷,卻偏偏與公主長(zhǎng)得像簸喂,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嫂丙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359