Python: Как определить цикл for для продолжения функции?
Иногда мне нужен следующий шаблон в цикле for
. Время от времени более одного раза в одном цикле:
try:
var = 'attempt to do something that may fail on a number of levels'
except Exception, e:
log(e)
continue
Теперь я не вижу приятного способа обернуть это в функцию, поскольку он не может return continue
:
def attempt(this):
try:
return this
except Exception, e:
log(e)
# 1. continue # <-- syntax error: continue not properly in loop or
# 2. return continue # <-- invalid syntax
# 3.
return False # <-- this sort of works, but makes me feel powerless
Если я return False
чем я мог:
var = attempt('to do something that may fail on a number of levels')
if not var:
continue
Но я не чувствую, что это справедливость. Я хочу передать цикл for continue
(или подделать его) из функции attempt
.
Ответы
Ответ 1
У Python уже есть очень хорошая конструкция для этого, и он не использует continue
:
for i in range(10):
try:
r = 1.0 / (i % 2)
except Exception, e:
print(e)
else:
print(r)
Я бы не стал больше гнездствовать, чем это, или ваш код скоро станет очень уродливым.
В вашем случае я, вероятно, сделаю что-то более похожее, так как намного легче unit test отдельные функции и flat лучше, чем вложенные:
#!/usr/bin/env python
def something_that_may_raise(i):
return 1.0 / (i % 2)
def handle(e):
print("Exception: " + str(e))
def do_something_with(result):
print("No exception: " + str(result))
def wrap_process(i):
try:
result = something_that_may_raise(i)
except ZeroDivisionError, e:
handle(e)
except OverflowError, e:
handle(e) # Realistically, this will be a different handler...
else:
do_something_with(result)
for i in range(10):
wrap_process(i)
Помните, что всегда улавливать определенные исключения. Если вы не ожидали, что какое-либо исключение будет выбрано, вероятно, небезопасно продолжать цикл обработки.
Изменить следующие комментарии:
Если вы действительно не хотите обрабатывать исключения, которые по-прежнему считаете плохими, поймите все исключения (except:
) и вместо handle(e)
просто pass
. На этом этапе wrap_process()
закончится, пропустив else:
-block, где выполняется настоящая работа, и вы перейдете к следующей итерации вашего for
-loop.
Помните, Ошибки никогда не должны проходить молча.
Ответ 2
Вся идея исключений заключается в том, что они работают на нескольких уровнях косвенности, т.е. если у вас есть ошибка (или любое другое исключительное состояние) внутри вашей иерархии вызовов, вы все равно можете поймать ее на более высоком уровне и обработать ее должным образом.
В вашем случае скажем, что у вас есть попытка функции(), которая вызывает функции try2() и try3() вниз по иерархии вызовов, а try3() может столкнуться с исключительным состоянием, которое должно привести к завершению основного цикла:/p >
class JustContinueException(Exception):
pass
for i in range(0,99):
try:
var = attempt() # calls attempt2() and attempt3() in turn
except JustContinueException:
continue # we don't need to log anything here
except Exception, e:
log(e)
continue
foo(bar)
def attempt3():
try:
# do something
except Exception, e:
# do something with e, if needed
raise # reraise exception, so we catch it downstream
Вы даже можете сами выпустить фиктивное исключение, которое просто вызовет завершение цикла и даже не будет зарегистрировано.
def attempt3():
raise JustContinueException()
Ответ 3
Может быть, вы хотите делать продолжение? Вы можете пойти и посмотреть, как Эрик Липперт объясняет им (если вы готовы к разуму, но на Python это может немного походить на это:
def attempt(operation, continuation):
try:
operation()
except:
log('operation failed!')
continuation()
Внутри вашей петли вы можете сделать:
attempt(attempt_something, lambda: foo(bar)) # attempt_something is a function
Ответ 4
Подумайте, что вы отображаете foo
для всех элементов, где attempt
работал. Таким образом, attempt
является фильтром, и его легко записать в виде генератора:
def attempted( items ):
for item in items:
try:
yield attempt( item )
except Exception, e:
log(e)
print [foo(bar) for bar in attempted( items )]
Ответ 5
Вы можете использовать это:
for l in loop:
attempt() and foo(bar)
но вы должны убедиться, что try() возвращает True или False.
Действительно, хотя ответ Johnsyweb, вероятно, лучше.
Ответ 6
Обычно я бы не опубликовал второй ответ, но это альтернативный подход, если вам действительно не нравится мой первый ответ.
Помните, что функция может возвращать tuple
.
#!/usr/bin/env python
def something_that_mail_fail(i):
failed = False
result = None
try:
result = 1.0 / (i % 4)
except:
failed = True # But we don't care
return failed, result
for i in range(20):
failed, result = something_that_mail_fail(i)
if failed:
continue
for rah in ['rah'] * 3:
print(rah)
print(result)
Я утверждаю, что try ... except ... else
- это путь, и вы не должны молча игнорировать ошибки. Предостережение emptor и все такое.
Ответ 7
Помимо контекста, я просто хочу кратко ответить на вопрос. Нет, функция не может continue
создать цикл, в который он может быть вызван. Это потому, что у него нет информации об этом контексте. Кроме того, это вызовет целый новый класс вопросов, например, что произойдет, если эта функция вызывается без окружающего цикла для обработки этого continue
?
НО функция может сигнализировать различными способами, что она хочет, чтобы вызывающий абонент continue
выполнял какой-либо цикл в настоящий момент. Разумеется, одним из способов является возвращаемое значение. Верните False
или None
, чтобы сигнализировать об этом, например. Другим способом сигнализации является повышение специальной Exception
:
class ContinuePlease(Exception): pass
def f():
raise ContinuePlease()
for i in range(10):
try:
f()
except ContinuePlease:
continue
Ответ 8
помещает цикл for вне try, кроме блока... simple...; -)
import sys
if '3.4' in sys.version:
from termcolor import colored
def list_attributes (имя_модуля): '' 'Импортируйте модуль перед вызовом этого func на it.s' '' для индекса, метод в перечислении (dir (module_name)): пытаться: метод = str (метод) module = 'email' выражение = модуль + '.' + метод print ('*' * len (выражение), '\n') print (str (index).upper() + '.', color (expression.upper(), 'red'), ', eval (выражение). dir(),'... ','\n'2) print ('' * len (выражение), '\n') print (eval (выражение + '. doc'), '\n' * 4, 'КОНЕЦ ОПИСАНИЯ ДЛЯ:' + expression.upper(), '\n' * 4) кроме (AttributeError, NameError): Продолжать еще: проходить в конце концов: передать
Ответ 9
Изменить: Удалил всю ту тупость, которую я сказал...
Последний ответ заключался в том, чтобы переписать все это, чтобы мне не нужно было так писать.