上下文管理器作为一个类与功能?

时间:2018-02-23 23:29:43

标签: python function class contextmanager

我一直在研究Python的contextmanager(更具体地说,Python 3的contextlib或其后端的contextlib2),我想知道将它们作为一个类与一个函数一起编写它们的优点/缺点是什么?

它们似乎都以相同的方式运行并以相同的方式处理异常。有许多很酷的实用程序,如ExitStack(),但这些实用程序似乎可以在作为类或函数编写的上下文管理器中实现。因此,我很难找到一个很好的理由,为什么人们想要将上下文管理器作为一个类写成一个类,当它们可以作为一个函数编写并且只是在上下文管理器装饰器上时。

这是我写的一个简单的例子,展示了做同样的事情:

# !/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!')

1 个答案:

答案 0 :(得分:0)

如果你不需要"详细"使用语法的课程,你不需要它,就这么简单。

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

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

将上下文管理器作为类写入的一种情况可能更紧凑是当用作上下文管理器的对象也是您可控制的类时,然后您可以更好地集成运行__enter____exit__在其生命周期中。例如,看到可以用作装饰器或上下文管理器的对象(unittest.mock.patch出现在我的脑海中)并不罕见。听起来只是"魔术"对用户而言,实现非常明确且定义良好:在这样一个对象的类中,它作为上下文管理器的逻辑在__enter__ / __exit__上,并且逻辑实现装饰器行为在__call__方法上。