【问题标题】:Context Managers as a class vs. function?上下文管理器作为一个类与函数?
【发布时间】:2021-10-22 00:35:18
【问题描述】:

我最近一直在研究 Python 的 contextmanager(更具体地说,是 Python 3 的 contextlib 或其反向移植的 contextlib2),我想知道将它们编写为类与函数的优点/缺点是什么?

它们似乎都以相同的方式运行并以相同的方式处理异常。有很多很酷的实用程序,例如 ExitStack(),但这些实用程序似乎可以在编写为类或函数的上下文管理器中实现。因此,我正在努力寻找一个很好的理由来解释为什么人们想要将上下文管理器详细地编写为一个类,而它们可以被编写为一个函数并且只是在 contextmanager 装饰器上打一巴掌。

这是我写的一个简单的例子来展示两者做同样的事情:

# !/usr/bin/python -u
# encoding: utf-8

from contextlib import contextmanager

# Function-based
@contextmanager
def func_custom_open(filename, mode):
    try:
        f = open(filename, mode)
        yield f
    except Exception as e:
        print(e)
    finally:
        f.close()

# Class-based
class class_custom_open(object):

    def __init__(self, filename, mode):
        self.f = open(filename, mode)

    def __enter__(self):
        return self.f

    def __exit__(self, type, value, traceback):
        self.f.close()


if __name__ == '__main__':

    # Function-based
    with func_custom_open('holafile_func.txt', 'w') as func_f:
        func_f.write('hola func!')

    # Class-based
    with class_custom_open('holafile_class.txt', 'w') as class_f:
        class_f.write('hola class!')

【问题讨论】:

  • 如果你想让你的上下文管理器成为除了上下文管理器之外的任何东西,你不能使用@contextmanager

标签: python function class contextmanager


【解决方案1】:

如果你不需要使用语法的“详细”类,你就不需要它,就这么简单。

两者都存在的原因是使用类的方式是上下文管理器在语言中工作的实际方式。任何在其类中具有__enter____exit__ 方法的对象都可以用作上下文管理器。

使用@contextmanager 并允许将上下文管理器声明为函数的方式只是 Python 标准库中的一种实用工具。装饰器产生的是一个同时具有这两种方法的对象。

将上下文管理器编写为类可能更紧凑的一种情况是,用作上下文管理器的对象也是您控制的类,然后您可以更好地集成运行__enter__和@987654325 @ 在其生命周期中。例如,可以看到可以用作装饰器或上下文管理器的对象并不少见(我想到了unittest.mock.patch)。对用户来说这听起来很“神奇”,但实现非常清晰且定义明确:在这样一个对象的类中,它充当上下文管理器的逻辑在 __enter__/__exit__ 上,并且实现装饰器行为的逻辑在 __call__ 方法上。

【讨论】:

    猜你喜欢
    • 2018-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-22
    相关资源
    最近更新 更多