有没有办法检测正在运行的代码是否正在上下文管理器内执行?

new*_*123 7 python contextmanager

正如标题所述,有没有办法做到这样的事情:

def call_back():
    if called inside context:
        print("running in context")
    else:
        print("called outside context")
Run Code Online (Sandbox Code Playgroud)

这将导致:

with CTM() as context:
    call_back()
call_back()

>>> "running in context"
>>> "called outside context"
Run Code Online (Sandbox Code Playgroud)

edd*_*313 1

正如@chepner 在问题评论中所写

inspect我认为,如果不使用该模块,就不可能。context.__enter__除了保证在执行之前和context.__exit__之后调用之外,with 语句中的代码块没有什么特别之处。

然后@larsks 建议,如果你可以控制上下文管理器......

...您可以更新一些全局或特定于对象的状态来指示您是否位于上下文管理器内。

这似乎是@new-dev-123最终采用的解决方案。

在这里你有这个解决方案:

class CTM:
    def __init__(self):
        self._is_in_context = False   
    def __enter__(self):
        self._is_in_context = True
        return self
    def __exit__(self, *args, **kwargs):
        self._is_in_context = False
    def call_back(self):
        if self._is_in_context:
            print("running in context")
        else:
            print("called outside context")
Run Code Online (Sandbox Code Playgroud)
>>> with CTM() as context:
...     context.call_back()
running in context
>>> context.call_back()
called outside context
Run Code Online (Sandbox Code Playgroud)

如果您希望多个方法具有相同的行为,或者将职责分开,则可以使用装饰器。

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 inner
    
class CTM:
    def __init__(self):
        self._is_in_context = False
    def __enter__(self):
        self._is_in_context = True
        return self
    def __exit__(self, *args, **kwargs):
        self._is_in_context = False
    @reveal_context
    def call_back(self):
        pass
Run Code Online (Sandbox Code Playgroud)