025、上下文管理器
本文最后更新于 68 天前,其中的信息可能已经过时,如有错误请发送邮件到wuxianglongblog@163.com

上下文管理器

读写文件时,如果一个文件被打开,且未被正常关闭,可能会出现一些意想不到的结果。

Python提供了上下文管理器的机制来解决这个问题,它通常与关键字with一起使用。对于上面的例子,用with语句调用的方式为:

with <expression>:
    <statements>
with open('my_file', 'w') as fp:
    # do stuff with fp
    data = fp.write("Hello world")

等价于:

fp = open('my_file', 'w')
try:
    # do stuff with f
    data = fp.write("Hello world")
finally:
    fp.close()

处理文件,线程,数据库,网络编程等等资源的时候,经常需要使用上面这样的代码形式,以确保资源的正常使用和释放。

上下文管理器需要<expression>中的结果能够支持.__enter__().__exit__()方法:

fp = open('my_file', 'w')
fp.__enter__
fp.__exit__

自定义上下文管理器

可以定义一个支持上述方法的自定义上下文管理器:

class TestManager(object):

    def __enter__(self):
        print("Entering")

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting")
with TestManager():
    print("Hello")
Entering
Hello
Exiting

如果在执行过程中抛出了异常,.exit()方法会先被执行,然后抛出异常:

with TestManager():
    print(1 / 0)
Entering
Exiting

---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

Input In [8], in ()
      1 with TestManager():
----> 2     print(1 / 0)

ZeroDivisionError: division by zero

方法.enter()的返回值

在读文件的例子中,在<statements>中使用文件对象时使用了as关键字的形式,将open()函数返回的文件对象赋给了f。事实上,as关键字只是将上下文管理器.__enter__()方法的返回值赋给了f,而文件对象的.__enter__()方法的返回值刚好是它本身:

fp = open('my_file', 'w')

fp.__enter__() is fp
True
fp.close()

一个通常的做法是将.__enter__()方法的返回值设为这个上下文管理器对象本身,也可以是其他值:

class TestManager(object):

    def __enter__(self):
        print("Entering")
        return "Hello"

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting")
with TestManager() as f:
    print(f)
Entering
Hello
Exiting

错误处理

__exit__()方法接受的参数中有一些错误信息,如果没有错误,这些参数为None,如果有错误,可以在这个方法里对一些错误进行处理:

class TestManager(object):

    def __enter__(self):
        print("Entering")

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting")
        if exc_type is not None:
            print(f"Exception: {exc_value}")
with TestManager() as f:
    print(1 / 0)
Entering
Exiting
Exception: division by zero

---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

Input In [14], in ()
      1 with TestManager() as f:
----> 2     print(1 / 0)

ZeroDivisionError: division by zero

如果不想让异常继续抛出,只需要将.__exit__()方法的返回值设为True

class TestManager(object):

    def __enter__(self):
        print("Entering")

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting")
        if exc_type is not None:
            print(f"Exception: {exc_value}")
        return True
with TestManager() as f:
    print(1 / 0)
Entering
Exiting
Exception: division by zero

清理临时文件:

%rm my_file
谨此笔记,记录过往。凭君阅览,如能收益,莫大奢望。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇