首页 > 解决方案 > 在 init 中使用 contextmanager

问题描述

在下面的代码中,我不明白为什么with super().__init__(*args, **kwargs):MyFileIO2 中的行会抛出有关丢失的错误,__exit__而 MyFileIO 类的一切工作都很好。我真的不明白在 init 内部或外部进行操作有什么区别。有人可以告诉我这里发生了什么吗?

import io

class MyFileIO(io.FileIO):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def __enter__(self, *args, **kwargs):
        f = super().__enter__(*args, **kwargs)
        print('first byte of file: ', f.read(1))
        return f

class MyFileIO2(io.FileIO):
    def __enter__(self, *args, **kwargs):
        f = super().__enter__(*args, **kwargs)
        print('first byte of file: ', f.read(1))
        return f

    def __init__(self, *args, **kwargs):
        with super().__init__(*args, **kwargs): # AttributeError: __exit__
            pass

path = 'some_file.bin'

with MyFileIO(path, 'rb'):
    pass

MyFileIO2(path, 'rb')

标签: pythonpython-3.xclasspython-3.5contextmanager

解决方案


您将需要在 上调用上下文管理器self,因为__init__实际上并没有返回任何内容。

class MyFileIO2(io.FileIO):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        with self:
             pass

    def __enter__(self, *args, **kwargs):
        f = super().__enter__(*args, **kwargs)
        print('First byte of file: ', f.read(1))
        return f

为了测试,我创建了一个内容为“hello world”的二进制文件。

_ = MyFileIO2(path, 'rb')    
# First byte of file:  b'h'

super().__init__所发生的是正在通过上下文管理器传递的返回值,因此您有效地拥有了这个:

with None:
     pass

AttributeError: __enter__

上下文管理器尝试调用对象__enter__上的方法NoneType,但这是一个无效的操作。


推荐阅读