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

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()

有人知道我如何实现这一目标吗?
谢谢!

PS我正在使用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()

但是我不想根据这些范围实施过多的内部结构(即如何将代码分为函数)。
有人有一些创意吗?

有帮助吗?

解决方案

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

您的工作没有错,但是您可以简化一点。

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

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

您的 scope 相反,可以是一个班级 __enter__ 方法返回有用的对象或 None 它将以相同的方式使用。

其他提示

以下似乎有效:

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 但是没有办法执行/删除冗余
  • 它可以从更深的功能中捕获和抑制与预期的更深函数(自定义异常可能会有所帮助,但这使整个构造仍然更加混乱)
  • 这并不比仅使用@mark Ransom的版本更清晰

我认为这不能做到。我尝试将上下文经理作为一类实施,但没有办法 力量 提出例外的块,随后会被 __exit__() 方法。

我的用例和您的用例相同,遇到了 有条件的库 自您发布问题以来,有人在当时有帮助。

从该网站中,其使用为:

with conditional(CONDITION, CONTEXTMANAGER()):
    BODY()
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top