Объект становится None при использовании менеджера контекста

Почему это не работает:

class X:
    var1 = 1
    def __enter__(self): pass
    def __exit__(self, type, value, traceback): pass

with X() as z:
    print z.var1

Я получил:

print z.var1
AttributeError: 'NoneType' object has no attribute 'var1'

Ответ 1

Измените определение X на

class X(object):
    var1 = 1
    def __enter__(self):
        return self
    def __exit__(self, type, value, traceback):
        pass

with присваивает возвращаемое значение метода __enter__() имени после as. Ваш __enter__() вернулся None, который был назначен z.

Я также изменил класс на класс нового стиля (что не критично, чтобы заставить его работать).

Ответ 2

См. docs для менеджеров контекста:

__enter__( ) Введите контекст среды выполнения и верните этот объект или другой объект, связанный с временем выполнения контекст. Значение, возвращаемое этим метод привязан к идентификатору в предложение as с операторами, использующими этот менеджер контекста. Пример контекстный менеджер, который возвращает себя файловый объект. Возврат файлов себя от __enter__(), чтобы позволить open() для использования в качестве контекста выражение в выражении a.

Пример менеджера контекста, который возвращает связанный объект. возвращено decimal.Context.get_manager(). Эти менеджеры устанавливают активную десятичную контекст к копии оригинала десятичный контекст, а затем вернуть копия. Это позволяет сделать изменения к текущему десятичному контексту в тело заявления с без влияющий на код вне утверждение.

Ваш метод __enter__ ничего не возвращает, что совпадает с возвратом None.

Ответ 3

Функция, которую вы определили между "с" и "как", должна иметь и иметь только одно возвращаемое значение. 'with' передаст значение встроенному методу __enter__().

Объект типа класса в Python не будет возвращать никакого значения, если оно не было определено при его вызове.

Точно так же, если вы вызвали объект типа класса с его методом, который ничего не возвращает, он также выбросит исключение.

Вы не можете написать так:

with open('file.txt').readlines() as lines:

Это сгенерировало два возвращаемых значения, и это даже не позволило передать одну переменную в Python.

Но это хорошо использовать:

with open('file.txt') as f:
    lines = f.readlines()