【python】上下文管理器和with语句

Python的上下文管理器和with语句使用详解 Python是一门设计优雅且强大的编程语言,其中with语句是用于简化资源管理的一种特殊语法结构。上下文管理器和with语句的结合使用,使得代码更为简洁和易读,同时有效地管理资源,避免资源泄漏。本文将详细介绍Python中的上下文管理器,解释其原理,并通过具体的示例展示如何使用with语句进行资源管理。 阅读详情

嗨,大家好,我是暴走的海鸽。

今天,我将向大家介绍上下文管理器和with语句的使用方法。

以下上下文管理器、with未作特殊说明时均为同步原语。

什么是上下文管理器和with

有人认为Python中的with语句是一个晦涩难懂的特性,但是只要你了解了其背后的原理,就不会感觉到神秘了。with语句实际上是非常有用的特性,有助于编写清晰易读的Python代码。

而上下文管理器存在的目的便是管理with语句,就像迭代器的存在是为了管理for语句一样。

那么,究竟 with 语句要怎么用,与之相关的上下文管理器(context manager)是什么,它们之间又有着怎样的联系呢?

在任何一门编程语言中,文件的输入输出、数据库的连接断开等,都是很常见的资源管理操作。但资源都是有限的,在写程序时,我们必须保证这些资源在使用过后得到释放,不然就容易造成资源泄露,轻者使得系统处理缓慢,重则会使系统崩溃。

在 Python 中,上下文管理器(Context Manager)是一种资源管理的机制,用于在使用资源(如文件、网络连接、数据库连接等)之前分配资源,然后在使用完毕后释放资源。with 语句是用来简化上下文管理器的使用的语法糖,使代码更加清晰和简洁。

一个典型的案例便是内置的open()函数

使用try/finally结构保证文件的最终关闭:

f = open('test.txt', 'w')
try:
    f.write('hello')
finally:
    f.close()

然而,这一套固定模板较为冗长,还容易漏写,代码可读性也较差,因此我们一般更倾向于with语句。

with open('test.txt', 'w') as f: 
    f.write('hello')

另外一个典型的例子,是 Python 中的 threading.lock 类。

比如我想要获取一个锁,执行相应的操作,完成后再释放,那么代码就可以写成下面这样:

some_lock = threading.Lock()
some_lock.acquire()
try:
    ...
finally:
    some_lock.release()

而对应的 with 语句,同样非常简洁:

some_lock = threading.Lock()
with somelock:
    ...

什么场景建议考虑使用上下文管理器和with语句

从前面的例子中可以看出,上下文管理器的常见用途是自动打开和关闭文件以及锁的申请和释放。

不过,你还可以在许多其他情况下使用上下文管理器,综合来看有以下几种场景:

1) 打开-关闭

  • 如果想自动打开和关闭资源,可以使用上下文管理器。
  • 例如,可以使用上下文管理器打开一个套接字并关闭它。

2) 锁定-释放

  • 上下文管理器可以帮助你更有效地管理对象的锁。它们允许你获取锁并自动释放锁。

3) 启动-停止

  • 上下文管理器还能帮助您处理需要启动和停止阶段的场景。
  • 例如,您可以使用上下文管理器启动计时器并自动停止。

4) 更改 - 重置

  • 上下文管理器可以处理更改和重置场景。

  • 例如,您的应用程序需要连接多个数据源。它有一个默认连接。
    要连接到另一个数据源:

    • 首先,使用上下文管理器将默认连接更改为新连接。
    • 第二,使用新连接。
    • 第三,完成新连接的操作后,将其重置回默认连接。

5) 进入 - 退出

  • 上下文管理器可以处理进入和退出的场景。

常见的上下文管理器和with语句使用

为了更充分地掌握和运用这一特性,一个较为有效的途径是深入研究该特性在各个广泛应用的场景中的实际运用。

上下文管理器和 with 语句在 Python 中的使用非常广泛,涵盖了许多不同的场景。以下是一些常见的上下文管理器和 with 语句的使用场景:

1.文件操作:open() 函数返回的文件对象就是一个上下文管理器,它负责文件的打开和关闭。with open("file.txt", "r") as file: 就是一个典型的使用案例。

with open("file.txt", "r") as file:
    content = file.read()

2.数据库连接:在数据库操作中,使用 with 语句可以确保在使用完数据库连接后正确地关闭连接,防止资源泄漏。

import sqlite3

with sqlite3.connect("mydatabase.db") as connection:
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM mytable")

3.网络连接:类似于数据库连接,确保在网络连接使用完毕后关闭连接是良好的实践。

import requests

url = 'https://www.example.com'

# 使用Session对象作为上下文管理器
with requests.Session() as session:
    # 发起GET请求
    response = session.get(url)

    # 在此处处理响应
    print(response.status_code)
    print(response.text)

# 在退出上下文时,底层连接会被关闭

4.线程锁:threading 模块中的 Lock 对象可以作为上下文管理器,确保在使用完锁之后正确释放。

import threading

lock = threading.Lock()

with lock:
# 执行需要线程同步的代码

5.文件锁:在多进程环境下,可以使用文件锁确保多个进程对同一文件的互斥访问。

import fcntl

with open("file.txt", "r") as file:
    fcntl.flock(file, fcntl.LOCK_EX)
    # 执行需要文件锁的代码
    fcntl.flock(file, fcntl.LOCK_UN)

6.时间测量:使用上下文管理器来测量代码块的执行时间。

import time


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

    def __exit__(self, exc_type, exc_value, traceback):
        self.end_time = time.time()
        elapsed_time = self.end_time - self.start_time
        print(f"Code executed in 0.0646 seconds")


with TimerContextManager():
# 执行需要测量时间的代码

7.测试资源管理:在测试中,可以使用上下文管理器确保在测试开始和结束时正确地分配和释放资源。

class TestContextManager:
    def __enter__(self):
        # 在测试开始时分配资源
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        # 在测试结束时释放资源


with TestContextManager() as test:
# 执行测试代码

这些只是很小的一部分示例,上下文管理器和 with 语句的使用可以根据具体的应用场景而变化。总体而言,它们是一种确保资源正确管理的强大方式,提高了代码的可读性和可维护性。

上下文管理器和with的本质

上面我们了解了一些常见的上下文管理器和with的用法,有内置的上下文管理器和自定义的上下文管理器。可能你已经从中看出点端倪了,不过不妨让我们深入的了解下这一特性的本质。

上下文管理器的实现

一个上下文管理器必须实现两个方法:__enter__ 和 __exit__。

  • __enter__(self):在进入 with 语句块时被调用,返回资源对象,该对象会被赋值给 as 后面的变量。
  • __exit__(self, exc_type, exc_value, traceback):在离开 with 语句块时被调用,用于资源的释放。如果 with 语句块中发生异常,异常的信息(异常类型(如ZeroDivisionError)、异常示例(如错误消息)、traceback对象)将作为参数传递给 __exit__ 方法。如果__exit__方法返回None或者True之外的值,with块中任何异常都会向上冒泡。

try/finally语句中调用sys.exec_info(),得到的便是__exit__接收的三个参数。因此可以在__exit__中对异常进行处理。

我们来看一个发生异常的例子,观察 __exit__ 方法拿到的异常信息是怎样的:

class TestContext:
    def __enter__(self):
        print("__enter__")
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        print("exc_type:", exc_type)
        print("exc_value:", exc_value)
        print("exc_tb:", exc_tb)
        print("__exit__")


with TestContext() as t:
    # 这里会发生异常
    a = 1 / 0
    print('t: %s' % t)
    
"""
__enter__
exc_type: <class 'ZeroDivisionError'>
exc_value: division by zero
exc_tb: <traceback object at 0x7fa1d2adfe40>
__exit__
Traceback (most recent call last):
  File "/mnt/d/jinzhuan/rss/tpl_hf.py", line 15, in <module>
    a = 1 / 0
ZeroDivisionError: division by zero
"""

可以在__exit__处理异常,这也是很多框架中用于消除大量try/exception/finally的手段之一,比如django中就有这样处理数据库操作异常时的代码,见文末源码。

with 语句

直接调用__enter__和__exit__方法是使用上下文管理器的方式之一,但是with 语句是一种更加简洁的处理上下文管理器的方式。它的语法如下:

with expression as variable:
    # code block
  • expression 返回一个上下文管理器对象。
  • variable 是一个变量,用于存储 expression 返回的上下文管理器对象。

在 with 语句块中,上下文管理器的 __enter__ 方法被调用,返回的对象赋值给 variable。当退出 with 语句块时,无论是正常退出还是因为异常,上下文管理器的 __exit__ 方法都会被调用。

import time


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

    def __exit__(self, exc_type, exc_value, exc_tb):
        self.end_time = time.time()
        elapsed_time = self.end_time - self.start_time
        print(f"Elapsed Time: 0.0646 seconds")


with TimerContextManager() as timer:
    # 在这里写你想要测量执行时间的代码
    for _ in range(1000000):
        pass

# 在这里 timer 对象不再可用,执行时间已经在 __exit__ 方法中输出

使用 with 语句可以确保资源的正确分配和释放,使代码更加简洁和可读。上下文管理器在文件操作、数据库连接、网络连接等场景中经常被使用。在 Python 标准库中,有一些内置的上下文管理器,比如 open() 函数返回的文件对象就是一个上下文管理器。

python 3.10后支持带括号的上下文管理器

with(  
   open("text1.txt", encoding="utf-8") as f1,  
   open("text2.txt", encoding="utf-8") as f2  
):  
  print(f1.read(), f2.read())

异步上下文管理器和async with的本质

异步上下文管理器

要创建异步上下文管理器,您需要定义.__aenter__()和.__aexit__()方法。

import aiohttp
import asyncio


class AsyncSession:
    def __init__(self, url):
        self._url = url

    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        response = await self.session.get(self._url)
        return response

    async def __aexit__(self, exc_type, exc_value, exc_tb):
        await self.session.close()


async def check(url):
    async with AsyncSession(url) as response:
        print(f"{url}: status -> {response.status}")
        html = await response.text()
        print(f"{url}: type -> {html[:17].strip()}")


async def main():
    await asyncio.gather(
        check("https://realpython.com"),
        check("https://pycoders.com"),
    )


asyncio.run(main())

# https://realpython.com: status -> 200
# https://pycoders.com: status -> 200
# https://pycoders.com: type -> <!doctype html>
# https://realpython.com: type -> <!doctype html

使用asyc with语句

async with是with语句的异步版本,可以使用它来编写依赖于异步代码的上下文管理器。

import aiohttp
import asyncio


async def check(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            print(f"{url}: status -> {response.status}")
            html = await response.text()
            print(f"{url}: type -> {html[:17].strip()}")


async def main():
    await asyncio.gather(
        check("https://realpython.com"),
        check("https://pycoders.com"),
    )


asyncio.run(main())


# https://realpython.com: status -> 200
# https://realpython.com: type -> <!doctype html
# https://pycoders.com: status -> 200
# https://pycoders.com: type -> <!doctype html>

contextlib包简化上下文管理器的实现和管理

contextlib 模块提供了一些实用工具,用于简化创建和操作上下文管理器。以下是一些常用的 contextlib 工具:

1.contextlib.contextmanager:

介绍: 这是一个装饰器,用于将一个生成器函数转化为上下文管理器。生成器的 yield 语句之前的代码块将在 __enter__ 方法中执行,而 yield 语句之后的代码块将在 __exit__ 方法中执行。

此装饰器本质: 我们先来看下这个装饰器的定义和帮助文档,其实讲的还是非常清楚的,巧妙的利用了生成器特性实现了上下文管理器。

def contextmanager(func):
  """@contextmanager decorator.

  Typical usage:

      @contextmanager
      def some_generator(<arguments>):
          <setup>
          try:
              yield <value>
          finally:
              <cleanup>

  This makes this:

      with some_generator(<arguments>) as <variable>:
          <body>

  equivalent to this:

      <setup>
      try:
          <variable> = <value>
          <body>
      finally:
          <cleanup>
  """
  @wraps(func)
  def helper(*args, **kwds):
      return _GeneratorContextManager(func, args, kwds)
  return helper
class _GeneratorContextManager(_GeneratorContextManagerBase,
                             AbstractContextManager,
                             ContextDecorator):
   """Helper for @contextmanager decorator."""

   def _recreate_cm(self):
       # _GCM instances are one-shot context managers, so the
       # CM must be recreated each time a decorated function is
       # called
       return self.__class__(self.func, self.args, self.kwds)

   def __enter__(self):
       # do not keep args and kwds alive unnecessarily
       # they are only needed for recreation, which is not possible anymore
       del self.args, self.kwds, self.func
       try:
           return next(self.gen)
       except StopIteration:
           raise RuntimeError("generator didn't yield") from None

   def __exit__(self, type, value, traceback):
       if type is None:
           try:
               next(self.gen)
           except StopIteration:
               return False
           else:
               raise RuntimeError("generator didn't stop")
       else:
           if value is None:
               # Need to force instantiation so we can reliably
               # tell if we get the same exception back
               value = type()
           try:
               self.gen.throw(type, value, traceback)
           except StopIteration as exc:
               # Suppress StopIteration *unless* it's the same exception that
               # was passed to throw().  This prevents a StopIteration
               # raised inside the "with" statement from being suppressed.
               return exc is not value
           except RuntimeError as exc:
               # Don't re-raise the passed in exception. (issue27122)
               if exc is value:
                   return False
               # Likewise, avoid suppressing if a StopIteration exception
               # was passed to throw() and later wrapped into a RuntimeError
               # (see PEP 479).
               if type is StopIteration and exc.__cause__ is value:
                   return False
               raise
           except:
               # only re-raise if it's *not* the exception that was
               # passed to throw(), because __exit__() must not raise
               # an exception unless __exit__() itself failed.  But throw()
               # has to raise the exception to signal propagation, so this
               # fixes the impedance mismatch between the throw() protocol
               # and the __exit__() protocol.
               #
               # This cannot use 'except BaseException as exc' (as in the
               # async implementation) to maintain compatibility with
               # Python 2, where old-style class exceptions are not caught
               # by 'except BaseException'.
               if sys.exc_info()[1] is value:
                   return False
               raise
           raise RuntimeError("generator didn't stop after throw()")

示例:

from contextlib import contextmanager


@contextmanager
def my_context():
    # Code before yield is __enter__
    print("Enter")
    yield
    # Code after yield is __exit__
    print("Exit")


with my_context():
    print("Inside the context")

yield后异常示例:

from contextlib import contextmanager


@contextmanager
def test():
    print('before')
    try:
        yield 'hello'
        # 这里发生异常必须自己处理异常逻辑否则不会向下执行
        a = 1 / 0
    finally:
        print('after')


with test() as t:
    print(t)
    
"""
before
hello
after
Traceback (most recent call last):
  File "/mnt/d/jinzhuan/rss/tpl_hf.py", line 16, in <module>
    print(t)
  File "/usr/lib/python3.8/contextlib.py", line 120, in __exit__
    next(self.gen)
  File "/mnt/d/jinzhuan/rss/tpl_hf.py", line 10, in test
    a = 1 / 0
ZeroDivisionError: division by zero
"""

2.contextlib.closing:

介绍: closing 是一个上下文管理器工具,用于确保在退出上下文时调用对象的close方法。通常,它用于处理那些没有实现上下文管理协议(__enter__和__exit__方法)的对象,但是有close方法的情况。

示例:

from contextlib import closing


class Test(object):

    # 定义了 close 方法才可以使用 closing 装饰器
    def close(self):
        print('closed')

    # with 块执行结束后 自动执行 close 方法


with closing(Test()):
    print('do something')

# Output:  
# do something  
# closed

从执行结果我们可以看到,with 语句块执行结束后,会自动调用 Test 实例的 close 方法。所以,对于需要自定义关闭资源的场景,我们可以使用这个方法配合 with 来完成。

3.contextlib.ExitStack:

介绍: ExitStack 是一个上下文管理器,它允许你动态地管理一组上下文管理器,无论这组管理器的数量是多少。它可以用于替代多个嵌套的 with 语句。

示例:

from contextlib import ExitStack


def example_function(file1_path, file2_path):
    with ExitStack() as stack:
        # 打开第一个文件
        file1 = stack.enter_context(open(file1_path, 'r'))

        # 打开第二个文件
        file2 = stack.enter_context(open(file2_path, 'r'))

        # 在此处进行文件处理,无需手动关闭文件


# 使用例子
example_function('file1.txt', 'file2.txt')

4.contextlib.suppress:

介绍: suppress 是一个上下文管理器,用于忽略指定的异常。它允许您执行代码块,即使在存在异常的情况下也能继续执行。

示例:

from contextlib import suppress

with suppress(ZeroDivisionError):
    # 尝试执行可能抛出异常的代码
    result = 10 / 0

# 不会中断程序执行,即使发生了ZeroDivisionError
print("Continuing with the program")

5.contextlib.redirect_stdout 和 contextlib.redirect_stderr:

介绍: 这两个上下文管理器允许您在代码块内重定向标准输出和标准错误流。

示例:

from contextlib import redirect_stdout, redirect_stderr
import io

# 示例1: 将标准输出重定向到文件
with open('output.txt', 'w') as f:
    with redirect_stdout(f):
        print("This goes to the file instead of the console.")

# 示例2: 将标准错误重定向到字符串
error_output = io.StringIO()
with redirect_stderr(error_output):
    print("This goes to the error_output StringIO instead of the console.")

# 获取重定向的标准错误的内容
error_contents = error_output.getvalue()
print("Captured error output:", error_contents)

# This goes to the error_output StringIO instead of the console.
# Captured error output:

6.contextlib.ContextDecorator:

介绍: ContextDecorator是一个用于创建同时兼具上下文管理器和装饰器功能的基类。

示例:

from contextlib import ContextDecorator


class TestCm(ContextDecorator):
    a = 12

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

    def __exit__(self, exc_type, exception, traceback):
        print("exit")
        TestCm.a = 12


@TestCm()
def play_testcm():
    TestCm.a = 8
    print("play_testcm, ", TestCm.a)


play_testcm()



# enter
# play_testcm,  8
# exit

7.contextlib.asynccontextmanager:

介绍: contextlib.asynccontextmanager是用于创建异步上下文管理器的装饰器。

示例:

import asyncio
from contextlib import asynccontextmanager


# 异步上下文管理器的例子
@asynccontextmanager
async def async_example():
    print("Enter async_example")

    # 在进入上下文时执行一些异步操作

    result = await asyncio.sleep(2)

    try:
        # 将资源(或状态)传递给上下文
        yield result
    finally:
        # 在退出上下文时执行一些异步操作
        print("Exit async_example")


# 使用异步上下文管理器
async def main():
    async with async_example() as result:
        # 在此处使用上下文中的资源
        print("Inside main:", result)


# 运行异步代码
asyncio.run(main())

# Enter async_example
# Inside main: None
# Exit async_example

这些工具使得使用上下文管理器更加方便和灵活。contextlib 是 Python 标准库中一个强大而灵活的模块,用于简化上下文管理器的使用。

关于contextlib包的更多使用技巧,请阅读源码或参考官方文档。

更多应用示例

自定义文件上下文管理类

class FileManager:
    def __init__(self, name, mode):
        print('calling __init__ method')
        self.name = name
        self.mode = mode 
        self.file = None
        
    def __enter__(self):
        print('calling __enter__ method')
        self.file = open(self.name, self.mode)
        return self.file


    def __exit__(self, exc_type, exc_val, exc_tb):
        print('calling __exit__ method')
        if self.file:
            self.file.close()
            
with FileManager('test.txt', 'w') as f:
    print('ready to write to file')
    f.write('hello world')
    
## 输出
calling __init__ method
calling __enter__ method
ready to write to file
calling __exit__ method

Redis分布式锁

import redis
from contextlib import contextmanager

# 假设已经创建了一个 Redis 连接
redis_client = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)


@contextmanager
def lock(_redis_client, lock_key, expire):
    try:
        _locked = _redis_client.set(lock_key, 'locked', ex=expire, nx=True)
        yield _locked
    finally:
        _redis_client.delete(lock_key)


# 使用 lock 上下文管理器
with lock(redis_client, 'locked', 3) as locked:
    if not locked:
        print("Failed to acquire lock. Exiting...")
    else:
        print("Lock acquired. Performing some operation...")
        # 在这里执行需要锁的操作

# do something...

Redis事务和管道

import redis
from contextlib import contextmanager

# 假设已经创建了一个 Redis 连接
redis_client = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)


@contextmanager
def pipeline(_redis_client):
    _pipe = _redis_client.pipeline()
    try:
        yield _pipe
        _pipe.execute()
    except Exception as exc:
        _pipe.reset()


# 使用 pipeline 上下文管理器
with pipeline(redis_client) as pipe:
    pipe.set('key1', 'a', ex=30)
    pipe.zadd('key2', {'a': 1})
    pipe.sadd('key3', 'a')

让我简要解释一下这段代码:

  1. pipeline 函数使用 @contextmanager 装饰器,使得该函数返回一个上下文管理器。
  2. 在 try 块内,创建了一个 Redis pipeline 对象 pipe。
  3. yield pipe 将这个 pipeline 对象传递给 with 语句中的 as 子句,这样在 with 代码块中可以使用这个 pipeline 对象。
  4. pipe.execute() 在 with 代码块结束时被调用,执行 Redis pipeline 中的所有命令。
  5. except 块内,如果在 with 代码块中发生了异常,通过 pipe.reset() 重置 pipeline 对象,确保不会执行之前的命令。

异步文件上下文管理器

import aiofiles
import asyncio


async def read_file_async(file_path):
    async with aiofiles.open(file_path, mode='r') as file:
        content = await file.read()
        print(content)

asyncio.run(read_file_async('example.txt'))

异步HTTP请求上下文管理器

import aiohttp
import asyncio


async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            data = await response.text()
            print(data)

asyncio.run(fetch_data('https://baidu.com'))

django中的DatabaseErrorWrapper上下文管理器源码

class DatabaseErrorWrapper:
    """
    Context manager and decorator that reraises backend-specific database
    exceptions using Django's common wrappers.
    """

    def __init__(self, wrapper):
        """
        wrapper is a database wrapper.

        It must have a Database attribute defining PEP-249 exceptions.
        """
        self.wrapper = wrapper

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
                DataError,
                OperationalError,
                IntegrityError,
                InternalError,
                ProgrammingError,
                NotSupportedError,
                DatabaseError,
                InterfaceError,
                Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
                raise dj_exc_value.with_traceback(traceback) from exc_value

    def __call__(self, func):
        # Note that we are intentionally not using @wraps here for performance
        # reasons. Refs #21109.
        def inner(*args, **kwargs):
            with self:
                return func(*args, **kwargs)
        return inner

总结

这篇文章深入探讨了 Python 上下文管理器的应用与实现。首先,我们对比了在没有使用 with 语句和使用 with 语句时操作文件的代码差异,明确了 with 语句的优势,使代码结构更为简洁。接着,我们深入研究了 with 语句的实现原理,强调只需实现 __enter__ 和 __exit__ 方法的实例,即可借助 with 语法块高效管理资源。

然后我们也简单了解了下异步上下文管理器和async with以管理资源。

进一步介绍了 Python 标准库中 contextlib 模块,它提供了更便捷的上下文管理器实现方式。我们学习了如何使用 contextmanager 、ContextDecorator装饰器和 closing 等方法来优雅地处理资源。最后,通过多个实际例子展示了上下文管理器在管理资源和执行前后逻辑方面的价值。

综上所述,通过在开发中广泛运用上下文管理器,我们能够显著提升代码结构和可维护性。因此,强烈推荐在项目中积极采用这一优秀的编程模式。

一起学习

欢迎大家关注我的账号,你的支持,是我更文的最大动力!

也欢迎关注我的公众号: 海哥python,领取更多python学习和面试资料。

微信号:fenggeniubi_2023

参考

《流畅的python》第一版及第二版
《深入理解python特性》
https://docs.python.org/3/library/contextlib.html
https://realpython.com/python-with-statement/
https://medium.com/@praba230890/a-guide-to-python-context-managers-aa7db1d28e87
https://book.pythontips.com/en/latest/context_managers.html

Python基础技能之python中的上下文管理器和with语句的使用 @本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 本篇文章主要介绍了Python中的上下文管理器和with语句的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 文章目录为什么需要上下文管理器?举两个例子:上下文管理器怎么使用?上下文管理实现机制上下文管理器实现 python2.5之后引入了上下文管理器(context manager),算是Python的黑魔法之一,它用于规定某个对象的使用范围。本文是针对于该功能的思考总结。 为什么需要上下文管理器? 首 阅读详情

相关推荐

【Python高级】详解with语句和上下文管理器

【Python高级】详解with语句和上下文管理器

全网粉丝30W+,优快云、稀土掘金人工智能领域签约作者,人工智能、大模型、Python 爬虫,商务合作,请私信沟通。 425

Python | 多线程死锁问题的巧妙解决方法

本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第25篇文章,我们一起来聊聊多线程开发当中死锁的问题。 死锁 死锁的原理非常简单,用一句话就可以描述完。就是当多线程访问多个锁的时候,不同的锁被不同的线程持有,它们都在等待其他线程释放出锁来,于是便陷入了永久等待。比如A线程持有1号锁,等待2号锁,B线程持有2号锁等待1号锁,那么它们永远也等不到执行的那天,这种情况就叫做死锁。 关于死锁有一个著名的问题叫做哲学家就餐问题,有5个哲学家围坐在一起,他们每个人需要拿到两个叉

TechFlow的博客 1033

Matlab实战:3种雷达间歇采样干扰的仿真与识别(附完整代码)

本文通过Matlab实战,详细仿真了雷达有源间歇采样干扰的三种核心样式:直接转发、重复转发和循环转发干扰。文章提供了完整的代码实现,并深入探讨了基于时频分析和循环平稳分析的特征提取与识别方法,为雷达抗干扰技术的学习与实践提供了清晰的工程实现路径。

weixin_29053695的博客 363

python基础 — 上下文管理器

自定义上下文管理器运行结果:自定义一个上下文管理器 MyContextManager ,包含__enter__和__exit__方法。分析运行结果可知其执行过程:首先执行类中的方法,它总是在进入代码块前被调用的接着就执行代码块——with语句下面的代码块离开的时候又调用类中的__exit__()...

个人博客 3039

欢乐熊大话蓝牙知识16:蓝牙是怎么找设备的?扫描与广播的“对话内幕”

蓝牙是怎么找设备的?扫描与广播的对话技术介绍

hoony123的博客 1380

西门子触摸屏教程wincc flexible2008 sp5 Smart V3 V4中文版软件

西门子触摸屏教程wincc flexible2008 sp5 Smart V3 V4中文版软件

liang007dudu的博客 1万+

Python学习笔记——上下文管理器与with

with与上下文管理协议 尽管大多数主流语言都支持类和对象,但几乎没有语言提供类似 Python的上下文管理协议 在处理文本文件(甚至数据库)时,有通用的“建立、处理、清理”模式 建立( setup):处理文件时,with语句会打开指定的文件,返回一个表示这个文件流的变量,这里即tasks变量 处理(do):就是与with语句关联的代码组,它们是“核心部分”,完成具体的工作 清理( teardown):用with打开一个文件时,它承诺当with的代码组结束时会关闭这个文件 最简单的例子是处理一个文本

Insomnia_X的博客 451

Win10插网线显示未识别网络的三种解决方法

本文介绍了三种解决Win10插网线显示未识别网络问题的方法:更新或重启网络设备驱动程序、重置Winsock目录、启用Network Setup Service服务。这些方法都是基于常见的网络问题和解决方案而设计的,适用于大多数Win10用户。如果你遇到了这一问题,可以按照上述步骤进行操作,相信一定能够找到解决问题的方法。需要注意的是,在进行任何操作之前,请务必备份重要数据以防万一。此外,如果你对计算机硬件或软件不熟悉,建议寻求专业人士的帮助以避免造成不必要的损失。

nntxthml的博客 6770

python的sqlite_让 Python 更加充分的使用 Sqlite3

4. 使用Context Managers(上下文管理器)即使在处理SQL事务的中间,也会发生讨厌的事情。为了避免手动处理回滚或提交,你可以简单地使用连接对象作为上下文管理器。 在以下示例中,我们创建了一个表,并错误地插入了重复的值:import sqlite3connection = sqlite3.connect(':memory:')with connection:connection.ex...

weixin_39517520的博客 110

SAP 批量修改 工艺路线 和 BOM

1、在运维的过程中经常会遇到用户需要批量更改组件,或者是批量更改数量,还是组件里面的一些标识,当处理这些批量数据处理的业务时,BOM的批量更改一个想到的就是CS20,但是CS20当BOM需要替换的时候就不是很适用。当前工作区域:选择 SAP_ITEM 对BOM行项目进行变更,工艺路线也是可以批量更改的,根据实际的业务进行选择,我这里选择的就是BOM的组件变更。5、本博客将使用新的一种方式进行BOM的批量变更,标准的事务代码:CEWB对BOM进行批量更改。3、使用LSMW的方式进行BOM的批量更改。

我小时候很黑的博客 4092

YOLOv11改进策略【Head】| AFPN渐进式自适应特征金字塔,增加针对小目标的检测头(附模块详解和完整配置步骤)

一、本文介绍 本文利用AFPN对YOLOv11的网络模型进行优化提升。AFPN采用渐近式融合及自适应空间融合操作。通过渐近式架构,逐步整合不同层级特征,有效避免非相邻层级间因语义差距过大导致的信息丢失或降级问题,确保在多尺度特征融合过程中既能保留高层语义信息,又能融入低层细节特征。本文将AFPN应用于YOLOv11中,并配置了针对小目标的检测头,能显著增强模型对不同尺度目标的检测能力,使其在复杂场景下更聚焦于目标物体特征,减少背景等无关信息的影响。 专栏目录:YOLOv11改进目录一览 | 涉及卷积层、

Limiiiing的博客 2717

理解 Python 中的上下文管理器:资源管理的利器

上下文管理器是一种设计模式,用于管理资源的生命周期。它主要用于保证在代码块执行前后对某些资源进行适当的初始化和清理。比如,在文件操作中,打开文件时需要初始化资源,文件使用完毕后需要关闭资源。上下文管理器帮助我们简化这些操作,减少资源泄露的风险。Python 中的上下文管理器通常通过with语句来使用。with语句会自动管理资源,确保无论代码块是正常执行还是抛出异常,都能正确地释放资源。你也可以自定义上下文管理器来处理自己的资源管理需求。自定义上下文管理器需要实现__enter__和__exit__方法。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 858

液态神经网络(Liquid Neural Networks)从线虫大脑到下一代 AI

液态神经网络(Liquid Neural Networks,LNN)是一类具有动态内部结构的神经网络,其灵感来源于生物神经系统,尤其是大脑中神经元如何以复杂、非线性的方式响应外部刺激。与传统神经网络不同,液态神经网络的每个神经元在处理输入时,不再是静态线性或非线性变换,而是基于一个微分方程模型进行响应。这种建模方式使神经元的行为具有时间连续性和动态适应性。换句话说,它不仅“记住”过去的信息,还能根据当前环境实时调整自身的动态特性,这对于感知、决策、预测等任务都非常关键。

hello.reader 7406

python | 一文掌握Python的上下文管理器和with语句

Python是一门设计优雅且强大的编程语言,其中with语句是用于简化资源管理的一种特殊语法结构。上下文管理器和with语句的结合使用,使得代码更为简洁和易读,同时有效地管理资源,避免资源泄漏。本文将详细介绍Python中的上下文管理器,解释其原理,并通过具体的示例展示如何使用with语句进行资源管理。

csdn_xmj的博客 1180

LPDDR4 JEDEC标准测试实例解析--写操作

LPDDR4的JEDEC标准一致性测试项详解以及实例分享,满满干货!感兴趣的小伙伴可以持续关注!!

一只豌豆象的博客 7773

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【python】详解上下文管理器和with语句

有人认为Python中的with语句是一个晦涩难懂的特性,但是只要你了解了其背后的原理,就不会感觉到神秘了。with语句实际上是非常有用的特性,有助于编写清晰易读的Python代码。而上下文管理器存在的目的便是管理with语句,就像迭代器的存在是为了管理for语句一样。那么,究竟 with 语句要怎么用,与之相关的上下文管理器(context manager)是什么,它们之间又有着怎样的联系呢?在任何一门编程语言中,文件的输入输出数据库的连接断开等,都是很常见的资源管理操作。

大模型教程的博客 808

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

python中的上下文管理器和with语句

引入: 打开一个文件并写入‘hello, world’,可用代码一和代码二实现: 代码一: f = open("hello.txt", 'w') try: f.write('hello, world') finally: f.close() 代码二: with语句通过在上下文管理器中封装try…finally语句的标准用法来简化异常处理 with open('hello.txt', 'w')...

_淡泊宁静的博客 407

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Python高级语法:with语句和上下文管理器

with语句和上下文管理器

weixin_71405027的博客 895

Python with语句和上下文管理器

Python with语句和上下文管理器 Python中的with语句和上下文管理器,是从2.5版本开始加入到Python语法中的。它能够让你的代码可读性更强并且错误更少。 一、with语法: 基本语法格式: with EXPR as VAR: BLOCK 2.1:普通栗子: 举个文件写入时的栗子,看简单看一下try、except、else、finally执行的顺序: try: f ...

Fe_cow的博客 331

Python 中的上下文管理器和with 语句

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的”清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。上下文管理协议(Context Management Protocol):包含方法 enter() 和 exit(),支持该协议的对象要实现这两个方法。上下文管理器(Context Manager) :支持上下文管理协议的对象,这种对象实现了 enter() 和 exit() 方法。上下文表达式(Context Expression) :with

daihaoxin的专栏 331

2 python with语句和上下文管理器

1. with语句的使用 向文件中写入数据的示例代码: 1、以写的方式打开文件 f = open(“1.txt”, “w”) 2、写入文件内容 f.write(“hello world”) 3、关闭文件 f.close() 代码说明: 文件使用完后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的 这种写法可能出现一定的安全隐患,错误代码如下: 1、以读的方式打开文件 f = open(“1.txt”, “r”) 2、读取文件内容 f.write(“hello wor

THE ORDER 314

Python学习之with语句和上下文管理器详解

本文和大家分享的主要是python的with语句和上下文管理器相关内容,一起来看看吧,希望对大家学习python有所帮助。   With语句的语法和原理   基本语法   with是用来操作上下文管理器的。   上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了 __enter__() 和 __exit__() 方法。上下文管理器定义执行 with 语

qq_38604641的博客 400

解释Python中的上下文管理器(with语句)的作用和用法

总之,Python中的上下文管理器(with语句)通过自动管理资源和简化异常处理,提高了代码的可读性、可维护性和安全性。通过定义自定义的上下文管理器类或使用内置的上下文管理器,我们可以更加优雅地处理资源获取与释放、异常处理等问题,使代码更加健壮和可靠。Python中的上下文管理器(with语句)是一个强大且方便的工具,它用于确保代码块的执行前后能够自动执行某些操作,如资源的获取与释放、异常的处理等。通过上下文管理器,我们可以更加优雅地管理资源,避免资源泄露和异常处理不当等问题。在上面的示例中,当进入。

wssc63262的博客 857

深入理解Python中的上下文管理器和with语句

上下文管理器是Python中的一种对象,用于在代码块执行前后定义一些设置或清理的操作。例如,当打开文件、获取锁或建立数据库连接等需要清理的操作时,上下文管理器会十分有用。上下文管理器必须定义两个特殊方法,__enter__和__exit__,分别在with语句开始和结束时被调用。python代码解读复制代码我们可以自定义上下文管理器来满足特定的需求。例如,我们可以创建一个上下文管理器来自动计时:python代码解读复制代码。

fzlhz的博客 115

理解python的with语句和上下文管理器

why with? 先看这样子的程序 myfile = open(r'C:\misc\data') try: for line in myfile: print(line) #...more code... finally: myfile.close() 程序尝试打印myfile的每行数据,最后关闭myfile文件 当然我们也有更加简单的写法,wi...

qq_18824345的博客 210

python with语句和自定义上下文管理器

with语句和自定义上下文管理器with语句自定义类使用上下文管理器contextlib的使用 with语句 with是一种上下文管理协议,with语句处理的对象有两个方法,一个是__enter__,另一个是__exit__ 在进入语句体之前会执行__enter__,语句体执行之后会自动执行__exit__ 举一个with的用法with open("test.txt", 'r') as f: infos = f.read() 自定义类使用上下文管理器 前面已经说到了with处理的对象包含_

cmy_top的博客 336
上一篇: pathlib,一个优雅的python库
下一篇: 善用Itertools,让你的python代码更整洁更优雅
海哥python
博客等级 码龄9年 1487粉丝 74原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海哥python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值