我应该如何正确地嵌套类的with
相关行为(例如,在派生或实例化时)?
这对我有用,但我想知道是否有专门的方法来做到这一点:
class class_a:
def __init__(self):
print('class_a::__init__')
def __enter__(self):
print('class_a::__enter__')
return self
def __exit__(self, type, exit, tb):
print('class_a::__exit__')
class class_b(class_a):
def __init__(self):
class_a.__init__(self)
print('class_b::__init__')
def __enter__(self):
class_a.__enter__(self)
print('class_b::__enter__')
return self
def __exit__(self, type, exit, tb):
class_a.__exit__(self, type, exit, tb)
print('class_b::__exit__', type, exit, tb)
with class_b():
print('ready')
try:
signal.pause()
except:
pass
以不同方式执行此操作的一种方法是实现class_b
,如下所示:
class class_b:
def __init__(self):
self._class_a_inst = class_a()
print('class_b::__init__')
def __enter__(self):
self._class_a_inst.__enter__()
print('class_b::__enter__')
return self
def __exit__(self, type, exit, tb):
self._class_a_inst.__exit__(type, exit, tb)
print('class_b::__exit__', type, exit, tb)
__enter__()
/ __exit__()
行为有什么不同吗?
答案 0 :(得分:3)
理想情况下,请使用contextlib.contextmanager
。对于派生的情况:
import contextlib
class context_mixin:
def __enter__(self):
self.__context = self.context()
return self.__context.__enter__()
def __exit__(self, *args):
return self.__context.__exit__(*args)
class class_a(context_mixin):
@contextlib.contextmanager
def context(self):
print('class_a enter')
try:
yield self
finally:
print('class_a exit')
class class_b(class_a):
@contextlib.contextmanager
def context(self):
with super().context():
print('class_b enter')
try:
yield self
finally:
print('class_b exit')
在Python 2中,super()
必须为super(class_b, self)
。
与您的代码相比,行为发生了变化:此代码在退出b
之前退出a
,这意味着范围嵌套。你已经编写了代码来按照其他顺序执行它们,尽管这很容易改变。通常它没有任何区别,但是当它确实很重要时,你通常会想要嵌套。因此,对于一个(公认的设计)示例,如果class_a
表示打开文件,而class_b
表示某种文件格式,则class_a
的退出路径将关闭文件,而退出class_b
的路径将写入尚未提交的任何缓冲更改。显然b
应该先发生!
对于持有另一个物体的情况:
class class_b(context_mixin):
def __init__(self):
self.a = class_a()
@contextlib.contextmanager
def context(self):
with self.a:
print('class_b enter')
try:
yield self
finally:
print('class_b exit')