As the title states, is there a way to do something like this:
def call_back():if called inside context:print("running in context")else:print("called outside context")
And this would result in:
with CTM() as context:call_back()
call_back()>>> "running in context"
>>> "called outside context"
As @chepner wrote in the comments of the question
Not [possible] without using the inspect
module, I'd think. There's nothing really special about the block of code in a with statement, aside from the guarantee that context.__enter__
will be called prior to executing it and context.__exit__
will be called after.
Then @larsks suggested that if you have control over the context manager...
... you could update some global or object-specific state to indicate whether you are inside the context manager or not.
This seems to be the solution finally adopted by @new-dev-123.
Here you have that solution:
class CTM:def __init__(self):self._is_in_context = False def __enter__(self):self._is_in_context = Truereturn selfdef __exit__(self, *args, **kwargs):self._is_in_context = Falsedef call_back(self):if self._is_in_context:print("running in context")else:print("called outside context")
>>> with CTM() as context:
... context.call_back()
running in context
>>> context.call_back()
called outside context
If you want the same behaviour for multiple methods, or to keep responsibilities separated, you can use a decorator.
def reveal_context(func):def inner(self, *args, **kwargs):if self._is_in_context:print("running in context")else:print("called outside context") return func(self, *args, **kwargs)return innerclass CTM:def __init__(self):self._is_in_context = Falsedef __enter__(self):self._is_in_context = Truereturn selfdef __exit__(self, *args, **kwargs):self._is_in_context = False@reveal_contextdef call_back(self):pass