Могу ли я использовать python с оператором для условного выполнения?

Я пытаюсь написать код, который поддерживает следующие семантики:

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

область, среди прочего (настройка, очистка), должна решить, должен ли этот раздел работать.
Например, если пользователь настроил программу на обход "action_name", то после вычисления Scope() do_some_other_stuff() будет выполняться без вызова do_something ().
Я попытался сделать это с помощью этого context manager:

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

но есть RuntimeError: generator didn't yield исключения (когда action is 'bypass').
Я ищу способ поддержать это, не возвращаясь к более подробной дополнительной реализации:

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

кто-нибудь знает, как я могу добиться этого?
Спасибо!

P. S. Я использую вместо python2.7

EDIT:
Решение не обязательно должно полагаться на with заявления. Я просто не знала, как выразить это без него. По сути, я хочу что-то в форме контекста (поддержка настройка и автоматическая очистка, не связанная с содержащейся логикой) и допускающая условное выполнение на основе параметров, переданных методу установки и выбранных в конфигурации.
Я также подумал о возможном решении с использованием декораторов. Пример:

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

но я не хочу навязывать слишком большую часть внутренней структуры (то есть, как код разделен на функции) на основе этих областей.
У кого-нибудь есть творческие идеи?

4 ответов


вы пытаетесь изменить ожидаемое поведение основные языковые конструкции. Это никогда не хорошая идея, это просто приведет к путанице.

нет ничего плохого в вашей работе, но вы можете немного упростить ее.

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

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

код scope вместо этого может быть класс,__enter__ метод возвращает полезный объект или None и он будет использоваться таким же образом.


Я не думаю, что это можно сделать. Я попытался реализовать context manager как класс, и просто нет способа силу блок для создания исключения, которое впоследствии будет подавлено __exit__() метод.


следующий, кажется, работает:

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

У меня тот же случай использования, что и у вас, и наткнулся на условное библиотека что кто-то услужливо разработал в то время, как вы разместили свой вопрос.

с сайта его использование выглядит так:

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