Экспериментируя с заплатами менеджер контекста во время выполнения, я заметил, что следующий код не ведет себя, как я ожидал:Почему `with` использует` __enter__` класса, а не объект?
class B:
def __enter__(self):
print('normal')
def __exit__(self, *stuff):
pass
def modify(self, x):
def other(self):
print('not normal: ', x)
self.__enter__ = other.__get__(self, type(self))
def main():
b = B()
b.__enter__()
b.modify('hi')
b.__enter__()
with b:
print('in with')
b.__enter__()
if __name__ == '__main__':
main()
Выполненного, это печатает:
normal
not normal: hi
normal
in with
not normal: hi
В то время как первая часть main
, с явными обращениями к __enter__
, ведет себя как и ожидалось (метод - правильно изменен), это означает, что это проигнорирует with
.
После некоторого поиска я обнаружил, что согласно PEP 343 показан пример перевода, который объясняет поведение; а именно перевод with mgr: ...
внутренне использует что-то вроде
type(mgr).__enter__(mgr)
вместо прямого вызова метода, как я делал выше.
И я задавался вопросом, почему это сделано. Это просто для того, чтобы люди, подобные мне, не возились, или есть более глубокая причина?
Возможно, я не полностью понял второй аргумент. Так что улучши его, если хочешь. – phg