Python學(xué)習(xí)打call第三十一天:上下文管理器

1.什么是上下文管理器

  • 先來說一下什么是上下文管理器吧迅皇,其實上下文管理器就是一個包裝任意代碼塊的對象榴徐,上下文管理器保證進入上下文管理器時技掏,每次代碼執(zhí)行的一致性署恍,當(dāng)退出上下文管理器時隔显,相關(guān)的資源會被正確的回收却妨。使用上下文管理器的好處是,一定能夠保證退出步驟的執(zhí)行括眠,通過 with 語句在編寫代碼時彪标,會使代碼變得更加簡潔,不用再去關(guān)閉文件

2.如何實現(xiàn)上下文管理器

我們通過實例來看一下如何實現(xiàn)上下文管理器:

class Student:
    def __init__(self):   # 第一步:首先進入上下文之前會調(diào)用初始化方法
        print('init')
        self.name = '張三'
        self.age = 27

    def __enter__(self):   # 第二步:然后進入上下文會調(diào)用__enter__方法掷豺,return返回的結(jié)果會通過as關(guān)鍵字賦值給后面的變量
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')      # 第四步:執(zhí)行完畢語句塊后捞烟,會調(diào)用__exit__方法退出上下文

with Student() as stu:
    print(stu)              # 第三步:調(diào)用了__enter__后,會執(zhí)行上下文的語句塊
  • 實現(xiàn)上下文管理器有兩種方式当船,一個是通過類實現(xiàn)__enter____exit__方法题画,也就是通過with語句進行上下文管理;

  • 還有一種方法是通過contextlib模塊裝飾器和生成器實現(xiàn)上下文管理生年;

with 語句實現(xiàn)的上下文管理

class Student:
    def __init__(self):
        print('init')
        self.name = '張三'
        self.age = 27

    def __enter__(self):   
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')      

# 即使在上下文語句中出現(xiàn)異常婴程,那么退出上下文的時候,也會執(zhí)行__exit__方法
with Student() as stu:
    raise Exception('自定義拋出一個異常')  
# 數(shù)據(jù)庫連接
class Data:
    def __init__(self):
        self.influxdb_client_1 = InfluxDBClient(host='1.1.1.1', port=8086, database='database1', )
        self.influxdb_client_2 = InfluxDBClient(host='2.2.2.2', port=8086, database='database1', )
  
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.influxdb_client_1.close()
        self.influxdb_client_2.close()
    
    def get_metrics(self, server_name):
        print('從influxdb中查詢到所有的metrics')
        return '將所有的metrics返回'

# 使用上下文管理查詢數(shù)據(jù)的過程, 即使中間拋出異常抱婉,也會執(zhí)行__exit__方法档叔,關(guān)閉數(shù)據(jù)庫連接
with Data() as data:
    data.get_metrics(server1)
  • with語句的語法為:with 表達(dá)式 [as 目標(biāo)]:代碼塊桌粉;

  • 當(dāng)with遇到上下文管理器,就會在執(zhí)行語句體之前衙四,先執(zhí)行上下文管理器的__enter__方法铃肯,然后再執(zhí)行語句體,執(zhí)行完語句體后传蹈,最后執(zhí)行__exit__方法押逼;

  • with語句支持嵌套,支持多個with子句惦界,它們兩者可以相互轉(zhuǎn)換挑格;

contextlib模塊實現(xiàn)上下文管理器

# 讓普通函數(shù)也可以使用上下文管理, 前提條件是add函數(shù)必須是生成器函數(shù)碌燕,且只有yield語句
from contextlib import contextmanager
@contextmanager
def add(x, y):
    print('__enter__')   # 第二部:調(diào)用__enter__
    yield x + y          # 第二部:返回__enter__函數(shù)的返回值給obj對象
    print('__exit__')    # 第四部:調(diào)用__exit__

with add(1,2) as obj:
    print(obj)            # 第三部:執(zhí)行上下文語句塊
  • contextlib模塊是Python標(biāo)準(zhǔn)庫提供的更加易用的上下文管理器工具模塊锦担;

  • 它是通過裝飾器實現(xiàn)的,不需要再創(chuàng)建類以及使用__enter____exit__這兩個方法坊饶,比with語句更加方便灾搏;

  • @contextmanager是一個裝飾器decorator挫望,它接收一個生成器generator,把生成器里yield的值賦給with...as后的變量狂窑,然后正常執(zhí)行with語句媳板;

  • closing 也是一個經(jīng)過 @contextmanager 裝飾的裝飾器,closing( )可以把對象變?yōu)樯舷挛膶ο笕缓笫褂脀ith語句(前提是這個對象能調(diào)用close( )方法r刃摇);

3.functools.total_ordering裝飾器

使用functools.total_ordering裝飾器可以很方便讓實例比較大兄枷铩:

from functools import total_ordering
@total_ordering
class Student:
    def __init__(self, price):
        self.__price = price

    @property
    def price(self):
        return self.__price
    # 如果需要比較大小巨缘,必須實現(xiàn)'< > <= >='一個其中的一個

    def __lt__(self, other):
        return self.__price < other.__price

stu1 = Student(10)
stu2 = Student(19)
print(stu1 < stu2)
print(stu1 > stu2)

# 輸出:
True
False
  • functools.total_ordering裝飾器是在python2.7的時候加上的,它是針對某個類如果定義了__lt__采呐、__le____gt__搁骑、__ge__這些方法中的至少一個斧吐,使用該裝飾器,則會自動的把其他幾個比較函數(shù)也實現(xiàn)在該類中
    例如上面的實例仲器,我們只定義了__lt__()方法煤率,本來如果我們使用,但是卻能使用__gt__()方法是會報錯的乏冀,但是用了functools.total_ordering裝飾器之后卻能使用__gt__()方法了蝶糯,是不是很方便;

參考:https://www.9xkd.com/user/plan-view.html?id=2808881948

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辆沦,一起剝皮案震驚了整個濱河市昼捍,隨后出現(xiàn)的幾起案子识虚,更是在濱河造成了極大的恐慌,老刑警劉巖妒茬,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件担锤,死亡現(xiàn)場離奇詭異,居然都是意外死亡乍钻,警方通過查閱死者的電腦和手機肛循,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來银择,“玉大人多糠,你說我怎么就攤上這事『瓶迹” “怎么了夹孔?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怀挠。 經(jīng)常有香客問我析蝴,道長,這世上最難降的妖魔是什么绿淋? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任闷畸,我火速辦了婚禮,結(jié)果婚禮上吞滞,老公的妹妹穿的比我還像新娘佑菩。我一直安慰自己,他們只是感情好裁赠,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布殿漠。 她就那樣靜靜地躺著,像睡著了一般佩捞。 火紅的嫁衣襯著肌膚如雪绞幌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天一忱,我揣著相機與錄音莲蜘,去河邊找鬼。 笑死帘营,一個胖子當(dāng)著我的面吹牛票渠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芬迄,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼问顷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杜窄,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肠骆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后羞芍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哗戈,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年荷科,在試婚紗的時候發(fā)現(xiàn)自己被綠了唯咬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡畏浆,死狀恐怖胆胰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刻获,我是刑警寧澤蜀涨,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站蝎毡,受9級特大地震影響厚柳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沐兵,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一别垮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扎谎,春花似錦碳想、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至预吆,卻和暖如春龙填,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拐叉。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工觅够, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人巷嚣。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像钳吟,于是被迫代替她去往敵國和親廷粒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容