My understanding was, that in order for this snippet to work:
with some_obj:
# do something
the some_obj
object must have __enter__
and __exit__
methods. And this is more or less the only requirement.
The following code demonstrates, that this is not correct:
class X:
pass
def my_enter(*args, **kwargs):
print("enter ", args, kwargs)
def my_exit(*args, **kwargs):
print("exit ", args, kwargs)
some_obj = X()
some_obj.__enter__ = my_enter
some_obj.__exit__ = my_exit
with some_obj:
print("inside with")
Even though the some_obj
obviously have attribute __enter__
the above code fails:
Traceback (most recent call last):
File "tst_with.py", line 17, in <module>
with some_obj:
AttributeError: __enter__
Interestingly, if I replace the two lines where I add methods to object with the following:
X.__enter__ = my_enter
X.__exit__ = my_exit
everything is ok.
Is there any reason why object having these magic methods is not enough for with
statement to work?
(I encountered this problem when crafting a mock object, and the original code was more sane than the code above.)