Могу ли я использовать Python с оператором для условного исполнения?
-
29-09-2019 - |
Вопрос
Я пытаюсь написать код, который поддерживает следующую семантику:
with scope('action_name') as s:
do_something()
...
do_some_other_stuff()
Область, среди прочего (настройка, очистка) должна решить, должен ли этот раздел работать.
Например, если пользователь настроил программу обойти 'action_name', чем, после Scope () оценивается DO_SOME_OTHER_STUFF (), будет выполняться без вызова DO_SOMETHETION ().
Я попытался сделать это с помощью этого диспетчера контекста:
@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()