首页 > 解决方案 > 在“with”语句中提取代码并将其从运行时中删除

问题描述

上下文

我正在尝试创建一个“环境”上下文管理器。可以将其视为根据上下文管理器的参数选择在本地或远程执行某些代码:

with PythonExecutor(env="local"):
    x = 1
    assert x == 1

将在进程中运行该代码。但是,将env参数更改为"remote"将连接到 SSH 并远程执行代码。

感谢这个 StackOverflow question,我设法将with块中的代码提取为方法中的字符串,__exit__并且 SSH 部分是微不足道的(与该问题无关)。

问题

如何防止with块内的代码在进程内运行?上下文管理器始终遵循:

  1. 打电话__enter__
  2. with在块内执行代码
  3. 打电话__exit__

这意味着即使我选择"remote"执行,代码也会在__enter__or中远程执行__exit__,但还是会在本地执行。换句话说,有没有办法跳过第 2 步?我开始研究运行时字节码操作,但它变得有点毛茸茸……</p>

也欢迎原始问题的其他解决方案(以优雅的方式在不同环境中运行代码)

标签: pythoncontextmanagerbytecode-manipulation

解决方案


这有点 hacky,需要稍微更改 with 块的代码,但是您可以让您的__enter__方法返回一个在env == 'remote'. 然后在远程情况下,您将收到本地错误,然后处理__exit__块中的所有其他内容。

class PythonExecutor:

    def __init__(self, env):
        self.env = env

    def __enter__(self):
        def switch():
            if self.env == 'remote':
                raise Exception # Probably some custom exception for only this purpose
        return switch

    def __exit__(self, exctype, excinst, exctb):
        # do ssh stuff here depending on exctype
        ...


with PythonExecutor(env='remote') as switch:
    switch()
    print('hello')

推荐阅读