with语句详解 1——with 语句的常见用法

相关链接:
1. with 语句的常见用法
2. contextlib模块提供上下文管理工具
3. 异步上下文管理器

一、上下文管理器

with 语句依赖于 上下文管理器(Context Manager),这是一个实现了 __enter__ 和 __exit__ 方法的对象。__enter__ 方法在进入 with 代码块时调用,通常用于获取资源;__exit__ 方法在退出 with 代码块时调用,通常用于释放资源。

二、with 语句的基本语法

    with context_manager as variable:

        # 执行代码块

其中,context_manager 是一个实现了上下文管理协议的对象,variable 是可选的,用于接收 enter 方法返回的值。

三、with 语句的常见用法

1 文件操作

通过 with 语句打开文件,可以在文件使用完毕后自动关闭,无需显式调用 close() 方法。

示例:读取文件内容
with open(‘example.txt’, ‘r’) as file:

content = file.read()

print(content)
示例:写入文件内容
with open('output.txt', 'w') as file:

    file.write("Hello, World!")

2. 网络连接

在网络编程中,with 语句可以用于管理网络连接,确保连接在使用完毕后自动关闭。例如,使用 requests 库发送 HTTP 请求时,可以通过 with 语句管理会话(Session)对象。

示例:使用 requests 发送 HTTP 请求
import requests

with requests.Session() as session:

    response = session.get('https://api.example.com/data')

    print(response.json())

在这个例子中,Session 对象会在 with 代码块结束时自动关闭,无需显示调用close()方法,确保资源被正确释放。

3. 数据库连接

在数据库操作中,with 语句可以用于管理数据库连接,确保连接在使用完毕后自动关闭。例如,使用 sqlite3 库连接 SQLite 数据库时,可以通过 with 语句管理连接对象。

示例:使用 sqlite3 连接数据库
import sqlite3

with sqlite3.connect('example.db') as conn:

    cursor = conn.cursor()

    cursor.execute('SELECT * FROM users')

    rows = cursor.fetchall()

    for row in rows:

        print(row)

在这个例子中,connect() 函数返回一个数据库连接对象,该对象实现了上下文管理协议。with 语句确保在代码块结束时自动调用 conn.close(),即使在执行 SQL 查询时发生异常,连接也会被正确关闭。

4. 锁机制

在多线程编程中,with 语句可以用于管理锁(Lock),确保锁在使用完毕后自动释放。例如,使用 threading.Lock 时,可以通过 with 语句管理锁对象。

示例:使用 threading.Lock 实现线程同步
import threading

lock = threading.Lock()

def thread_function():
   with lock:
       print(f"Thread {threading.current_thread().name} is running")

threads = []
for i in range(5):
   t = threading.Thread(target=thread_function, name=f"Thread-{i+1}")
   threads.append(t)
   t.start()

for t in threads:
   t.join()

在这个例子中,lock 对象会在 with 代码块结束时自动释放,确保多个线程不会同时访问共享资源,从而避免竞态条件。

5. 自定义上下文管理器

除了内置的上下文管理器,你还可以通过实现 __enter__ 和 __exit__ 方法来自定义上下文管理器。这使得 with 语句可以用于更广泛的应用场景。

示例:自定义上下文管理器

假设我们想创建一个上下文管理器来记录某个代码块的执行时间。我们可以定义一个类 Timer,并在其中实现 __enter__ 和 __exit__ 方法。

import time

class Timer:
   def __enter__(self):
       self.start_time = time.time()
       return self

   def __exit__(self, exc_type, exc_value, traceback):
       end_time = time.time()
       elapsed_time = end_time - self.start_time
       print(f"Elapsed time: {elapsed_time:.2f} seconds")

# 使用自定义上下文管理器
with Timer():
   time.sleep(2)

在这个例子中,Timer 类实现了上下文管理协议。__enter__ 方法记录开始时间,__exit__ 方法计算并打印经过的时间。with 语句确保在代码块结束时自动调用 __exit__ 方法,从而实现对代码块执行时间的精确测量。

6. 多个上下文管理器

with 语句支持同时管理多个上下文管理器,只需将它们用逗号分隔即可。这对于需要同时管理多个资源的场景非常有用。

示例:同时管理多个文件

假设我们需要同时读取两个文件的内容并进行比较。我们可以使用 with 语句同时管理两个文件对象。

with open('file1.txt', 'r') as f1, open('file2.txt', 'r') as f2:
   content1 = f1.read()
   content2 = f2.read()
   if content1 == content2:
       print("Files are identical")
   else:
       print("Files are different")

在这个例子中,with 语句同时管理两个文件对象 f1 和 f2,确保它们在代码块结束时自动关闭。

7. 异常处理

with 语句不仅可以管理资源,还可以捕获和处理异常。__exit__ 方法可以接受三个参数:exc_type、exc_value 和 traceback,分别表示异常类型、异常值和堆栈跟踪。如果 __exit__ 方法返回 True,则表示异常已被处理,不会传播到外部;如果返回 False 或不返回任何值,则异常会继续传播。

示例:捕获异常
class ClsContext:
    def __enter__(self):
        print("上下文管理器 __enter__()")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"上下文管理器 __exit__() exc_type={exc_type};exc_val={exc_val};exc_tb={exc_tb}")
        return True

    def test(self):
        print("上下文管理器 test() 1")
        try:
            json.loads('{"a":')
        except json.JSONDecodeError as e:
            print("上下文管理器 test() json.loads error")
            raise json.JSONDecodeError() from e
        print("上下文管理器 test() 2")

with ClsContext() as cc:
    print("with语句中的代码块 1")
    cc.test()
    print("with语句中的代码块 2")
输出:
上下文管理器 __enter__()
with语句中的代码块 1
上下文管理器 test() 1
上下文管理器 test() json.loads error
上下文管理器 __exit__() exc_type=<class 'TypeError'>;exc_val=JSONDecodeError.__init__() missing 3 required positional arguments: 'msg', 'doc', and 'pos';exc_tb=<traceback object at 0x000001F0659014C0>

4. 参考资料

https://blog.csdn.net/zhaoxilengfeng/article/details/144382104


下一篇: 2. contextlib模块提供上下文管理工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值