Могу ли я использовать 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()