提取 "with" 语句中的代码并将其从运行时删除

Extract the code in a "with" statement and remove it from runtime

上下文

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

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

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

感谢 ,我设法将 with 块中的代码提取为 __exit__ 方法中的字符串,并且 SSH 部分很简单(与该问题无关) ).

问题

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

  1. 呼叫__enter__
  2. 执行 with 块中的代码
  3. 呼叫__exit__

这意味着即使我选择"remote"执行,代码会在__enter____exit__远程执行,但仍然会在本地执行。换句话说,有什么方法可以跳过第 2 步吗?我开始研究 运行 时间字节码操作,但它变得有点毛茸茸了……

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

functions 上使用装饰器怎么样? (您确实说过欢迎使用其他解决问题的方法...)

def remote(func):
    def execute():
        print(f"running {func.__name__} remotely")
        return func()

    return execute

@remote
def func():
    print("hello")

func()

或者对于相同的语义:

def Env(env="local"):
    if env == "remote":
        return remote
    else:
        return lambda x: x

@Env("remote")
def func2():
    print("hello again")

@Env("local")
def func3():
    print("hello again")

func2()
func3()

我知道你几乎肯定想到过这种方法并出于某种原因拒绝了它,但偶尔,值得一提。

我不知道是否可以将 with 块的内容放入某种类似函数的东西中。如所写,此方法当然需要您将代码定义为函数。

它有点老套,需要稍微更改 with 块的代码,但您可以使 __enter__ 方法 return 成为一个在 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')