In python, there are many functions that work as both standard functions and context managers. For example open()
can be called either as:
my_file=open(filename,'w')
or
with open(filename,'w') as my_file:
Both giving you a my_file
object that can be used to do whatever you need to. In general the later is preferable, but there are times when one might want to do the former as well.
I've been able to figure out how to write a context manager, either by creating a class with __enter__
and __exit__
functions or by using the @contextlib.contextmanager
decorator on a function and yield
rather than return
. However, when I do this I can no longer use the function straight - using the decorator, for example, I get a _GeneratorContextManager
object back rather than the result that wanted. Of course, if I made it as a class, I'd just get an instance of the generator class, which I'd assume is essentially the same thing.
So how can I design a function (or class) that works as either a function, returning an object, or a context manager, returning a _GeneratorContextManager
or the like?
edit:
For example, say I have a function like the following (this is HIGHLY simplified):
def my_func(arg_1,arg_2):
result=arg_1+arg_2
return my_class(result)
So the function takes a number of arguments, does stuff with them, and uses the result of that stuff to initialize a class, which it then returns. End result is I have an instance of my_class
, just like I would have a file
object if I had called open
. If I want to be able to use this function as a context manager, I can modify it like so:
@contextlib.contextmanager
def my_func(arg_1,arg_2):
result=arg_1+arg_2 # This is roughly equivalent to the __enter__ function
yield my_class(result)
<do some other stuff here> # This is roughly equivalent to the __exit__function
Which works just fine when calling as a context manager, but I no longer get an instance of my_class
when calling as a straight function. Perhaps I'm just doing something wrong?
Edit 2:
Note that I do have full control over my_class
, including the ability to add functions to it. From the accepted answer below, I was able to infer that my difficulty stemmed from a basic misunderstanding: I was thinking that whatever I called (my_func
in the example above) needed to have the __exit__
and __enter__
functions. This is not correct. In fact, it's only what the function returns (my_class
in the above example) that needs the functions in order to work as a context manager.