编程语言
首页 > 编程语言> > Python的“ with”语句:使用__enter __ / __ exit__正确嵌套/派生类

Python的“ with”语句:使用__enter __ / __ exit__正确嵌套/派生类

作者:互联网

如何正确嵌套与类相关的行为(例如,在派生或实例化时)?

这对我有用,但我想知道是否有专用的方法可以做到这一点:

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 __()行为有什么区别吗?

解决方法:

理想情况下,使用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).

与您的代码相比,行为有所变化:此代码在退出a之前先退出b,这意味着范围嵌套.您已经编写了代码以其他顺序执行操作,尽管更改起来很容易.通常它没有什么区别,但是当确实重要时,您通常希望将其嵌套.因此,对于一个(公认的)示例,如果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')

标签:derived-class,with-statement,python
来源: https://codeday.me/bug/20191119/2035506.html