Python - 上下文管理器协议

  • with 语句的目的是简化try/finally ,即便由于异常,return,sys.exit()调用而终止,也会执行指定的操作
  • 上下文管理器协议包含__enter__和__exit__ 两个方法
  • with 语句开始执行时会在上下文管理器对象上调用__enter__方法
  • with 语句运行结构后会在上下文管理器对象上调用__exit__方法,以此扮演finally子句的角色

示例:

import pymysql.cursors

# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             database='db',
                             cursorclass=pymysql.cursors.DictCursor)

with connection:
    with connection.cursor() as cursor:
        # Create a new record
        sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
        cursor.execute(sql, ('webmaster@python.org', 'very-secret'))

    # connection is not autocommit by default. So you must commit to save
    # your changes.
    connection.commit()

    with connection.cursor() as cursor:
        # Read a single record
        sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s"
        cursor.execute(sql, ('webmaster@python.org',))
        result = cursor.fetchone()
        print(result)

connection 对象实现了上下文管理器协议:

cursor 对象也实现了上下文管理器协议:

最常见的例子是确保关闭文件对象

>>> with open('package-lock.json') as fp:
...     src = fp.read(60)
...
>>> len(src)
60
>>> fp    # fp 绑定打开的文件,因为文件的__enter__方法返回self
<_io.TextIOWrapper name='package-lock.json' mode='r' encoding='cp936'>
>>> fp.closed,fp.encoding  # 可以读取fp对象的属性
(True, 'cp936')
>>> fp.read(60)   # 但是不能使用fp继续读取文本,因为在with块的末尾,Python 调用TextIOWrapper.__exit__方法把文件关闭了
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
>>>

with open('package-lock.json') as fp: 求解 with 后面表达式得到的结果是上下文管理器对象。不过绑定到目标变量(在as子句中)上的值 是在上下文管理器对象上调用__enter__ 方法返回的结果

碰巧,open()函数返回一个TextIOWrapper 实例,而该实例的__enter__方法返回self。不过,其他类的__enter__方法可能会返回其他对象,而不返回上下文管理器实例

不管控制流以哪种方式退出with块,都在上下文管理器对象上调用__exit__方法,而不是在__enter__方法返回的对象上调用

with 语句的as子句是可选的。对open函数来说,必须加上as子句,以便获取文件的引用,在引用上调用方法。不过,有些上下文管理器返回None,因为没有什么有用的对象能提供给用户

import sys

class LookingGlass:
    def __enter__(self):
        self.original_write = sys.stdout.write
        sys.stdout.write = self.reverse_write
        return 'JABBERWOCKY'

    def reverse_write(self,text):
        self.original_write(text[::-1])


    def __exit__(self, exc_type, exc_val, traceback):
        sys.stdout.write = self.original_write
        if exc_type is ZeroDivisionError:
            print('Please DO NOT divide by zero!')
            return True

if __name__ == '__main__':
    with LookingGlass() as what:   # 1
        print('Alice,Kitty and Snowdrop')  # 2
        print(what)  
    print(what)  # 3
    print('Back to normal!')   # 4
    
# out:
'''
pordwonS dna yttiK,ecilA
YKCOWREBBAJ
JABBERWOCKY
Back to normal!
'''

1.这个上下文管理器是一个LookingGlass 实例,Pyhton 在上下文管理器上调用__enter__方法,把返回结果绑定到what上
2.打印一个字符串,然后打印what 变量的值。打印处的内容都是反向的
3.现在with块执行完毕。可以看到,__enter__方法的返回值,即存储在what 变量中的值,是字符串'JABBERWOCKY'.
4.输出不再是反向的了

posted @   chuangzhou  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示