类实例中的上下文管理器

时间:2016-01-28 16:00:42

标签: python

我想创建一个特定于另一个类的实例的上下文管理器类。我可以通过调用创建类的方法来实现,但我不确定这是最好,最好的方法:

class MyClass(object):
    def __init__(self):
        self.level = 0
        self.Nest = self.create_context_manager()
    def inclev(self):
        self.level += 1
    def declev(self):
        self.level -= 1

    def create_context_manager(self):
        self2 = self
        class Nest(object):
            def __init__(self):
                pass
            def __enter__(self):
                self2.inclev()
            def __exit__(self, exc_type, exc_value, traceback):
                self2.declev()
        return Nest

# Manually increase/decrease level
my_instance = MyClass()
print(my_instance.level)
my_instance.inclev()
print(my_instance.level)
my_instance.inclev()
print(my_instance.level)
my_instance.declev()
print(my_instance.level)
my_instance.declev()
print(my_instance.level)

# Use instance-specific context manager
other_instance = MyClass()
print(other_instance.level)
with other_instance.Nest():
    print(other_instance.level)
    with other_instance.Nest():
        print(other_instance.level)
    print(other_instance.level)
print(other_instance.level)

1 个答案:

答案 0 :(得分:4)

为什么需要嵌套类?只需让主对象直接实现上下文管理协议:

class MyClass(object):
    def __init__(self):
        self.level = 0
    def inclev(self):
        self.level += 1
    def declev(self):
        self.level -= 1

    __enter__ = inclev  # For __enter__, just alias inclev, no need for wrapper
    def __exit__(self, exc_type, exc_value, traceback):
        self.declev()

然后只需使用它:

with other_instance:
    print(other_instance.level)
    with other_instance:
        print(other_instance.level)
    print(other_instance.level)

如果您确实需要将上下文管理器协议作为名为Nest的构造事物,您仍然可以使用contextlib中的内置函数简化:

from contextlib import contextmanager

class MyClass(object):
    def __init__(self):
        self.level = 0
    def inclev(self):
        self.level += 1
    def declev(self):
        self.level -= 1

    @contextmanager
    def Nest(self):
        self.inclev()
        try:
            yield
        finally:
            self.declev()