Используйте contextmanager внутри init - PullRequest
0 голосов
/ 24 декабря 2018

В приведенном ниже коде я не понимаю, почему строка 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')

1 Ответ

0 голосов
/ 24 декабря 2018

Вам нужно будет вызвать диспетчер контекста на 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, но это недопустимая операция.

...