【问题标题】:Can I use python with statement for conditional execution?我可以使用带有语句的python进行条件执行吗?
【发布时间】:2010-11-30 13:37:53
【问题描述】:

我正在尝试编写支持以下语义的代码:

with scope('action_name') as s:
  do_something()
  ...
do_some_other_stuff()

范围,除其他外(设置、清理)应决定此部分是否应运行。
例如,如果用户将程序配置为绕过“action_name”,那么在评估 Scope() 之后,do_some_other_stuff() 将在不先调用 do_something() 的情况下执行。
我尝试使用这个上下文管理器来做到这一点:

@contextmanager
def scope(action):
  if action != 'bypass':
    yield

但得到RuntimeError: generator didn't yield 异常(当action'bypass' 时)。
我正在寻找一种方法来支持这一点,而不会退回到更冗长的可选实现:

with scope('action_name') as s:
  if s.should_run():
    do_something()
    ...
do_some_other_stuff()

有谁知道我如何做到这一点?
谢谢!

附:我正在使用python2.7

编辑:
解决方案不一定要依赖with 语句。没有它,我只是不知道如何表达它。本质上,我想要上下文形式的东西(支持设置和自动清理,与包含的逻辑无关)并允许基于传递给设置方法并在配置中选择的参数进行条件执行。
我还考虑了使用装饰器的可能解决方案。示例:

@scope('action_name') # if 'action_name' in allowed actions, do:
                      #   setup()
                      #   do_action_name()
                      #   cleanup()
                      # otherwise return
def do_action_name()
  do_something()

但我不想基于这些范围强制执行过多的内部结构(即代码如何划分为函数)。
有人有什么创意吗?

【问题讨论】:

  • with is not if ...你可以写s.do_something()并让上下文管理器返回一个什么都不做的对象。
  • 也想过,但还是希望能找到优雅的解决方案……
  • 另外,我对这个范围内的代码(例如,do_something())一无所知。

标签: python with-statement


【解决方案1】:

您正在尝试修改基本语言结构的预期行为。这绝不是一个好主意,只会导致混乱。

您的解决方法没有问题,但您可以稍微简化一下。

@contextmanager 
def scope(action): 
  yield action != 'bypass'

with scope('action_name') as s: 
  if s: 
    do_something() 
    ... 
do_some_other_stuff() 

您的scope 可以改为一个类,其__enter__ 方法返回一个有用的对象或None,并且它会以相同的方式使用。

【讨论】:

  • 谢谢。 (不是试图在这里开始关于 python 上下文语义的辩论,)我不同意“基本语言构造的预期行为”部分。对我来说,很明显可以跳过上下文管理器的“屈服”部分。直到我发现“没有屈服”异常。我认为语言应该处理它,也许通过从 enter 抛出预定义的异常类型,类似于 next() 方法的 StopIteration 异常。
【解决方案2】:

以下似乎有效:

from contextlib import contextmanager

@contextmanager
def skippable():
    try:
        yield
    except RuntimeError as e:
        if e.message != "generator didn't yield":
            raise

@contextmanager
def context_if_condition():
    if False:
        yield True

with skippable(), context_if_condition() as ctx:
    print "won't run"

注意事项:

  • 需要有人想出更好的名字
  • context_if_condition 不能在没有 skippable 的情况下使用,但无法强制执行/删除冗余
  • 它可以从比预期更深的函数中捕获和抑制 RuntimeError(自定义异常可能会有所帮助,但这会使整个构造更加混乱)
  • 这并不比仅使用 @Mark Ransom 的版本更清晰

【讨论】:

    【解决方案3】:

    我不认为这是可以做到的。我尝试将上下文管理器实现为一个类,但无法强制块引发异常,该异常随后会被__exit__() 方法压制。

    【讨论】:

    • 我有那种感觉。我希望可以使用我通常在这些情况下找到的一些 python 魔法来解决它。不过,这似乎是一个不错的功能。也许我可以要求它作为增强功能... :)
    【解决方案4】:

    我和你有同样的用例,并且遇到了conditional library,自从你发布你的问题以来,有人帮助开发了这个conditional library

    从网站来看,它的用途是:

    with conditional(CONDITION, CONTEXTMANAGER()):
        BODY()
    

    【讨论】:

    • 这不是解决方案。 conditional 库将条件应用于是否输入了给定的 上下文管理器。无论如何,主体总是被执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 2015-01-08
    • 2011-01-12
    • 1970-01-01
    相关资源
    最近更新 更多