I\'d like to write a function similar to open
. I\'d like to be able to call it with with
, but also without with
.
When I use
You have this:
@contextmanager
def versioned(file_path, mode):
# some setup code
yield versioned_file
# some teardown code
Your basic problem of course is that what you yield
from the context manager comes out of the with
statement via as
, but is not the object returned by your function. You want a function that returns something that behaves like the object open()
returns. That is to say, a context manager object that yields itself.
Whether you can do that depends what you can do with the type of versioned_file
. If you can't change it then you're basically out of luck. If you can change it then you need to implement the __enter__
and __exit__
functions as specified in PEP 343.
In your example code, though, it already has it, and your teardown code is the same as what it does itself on context exit already. So don't bother with contextlib at all, just return the result of open()
.
For other examples where you do need __enter__
and __exit__
, if you like the contextlib style (and who doesn't?) you can bridge the two things. Write a function context
that's decorated with @contextmanager
and yields self
. Then implement:
def __enter__(self):
self.context = context() # if context() is a method use a different name!
return self.context.__enter__()
def __exit__(self, *args):
return self.context.__exit__(*args)
It's basically up to you whether you find this better or worse than separating out the setup code into __enter__
and the teardown code into __exit__
. I generally find it better.