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
(или фейк) внутри
9 ответов
Python уже имеет очень хорошую конструкцию для этого, и она не использует continue
:
for i in range(10):
try:
r = 1.0 / (i % 2)
except Exception, e:
print(e)
else:
print(r)
Я бы не стал гнезда больше, чем это, хотя, или ваш код скоро станет очень уродливым.
в вашем случае я бы, вероятно, сделал что-то более подобное, так как гораздо проще тестировать отдельные функции и 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:
-блок, где реальная работа делается, и вы пойдете к следующей итерации for
-loop.
имейте в виду, ошибки никогда не должны пройти молча.
вся идея исключений заключается в том, что они работают на нескольких уровнях косвенности, т. е., если у вас есть ошибка (или любая другая исключительных state) глубоко внутри иерархии вызовов вы все равно можете поймать его на более высоком уровне и обработать его должным образом.
в вашем случае, скажем, у вас есть функция attempt (), которая вызывает функции attempt2 () и attempt3() вниз по иерархии вызовов, и attempt3 () может столкнуться с исключительным состоянием, которое должно вызвать основной цикл прекратить:
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()
может быть, ты хочешь продолжения? Вы могли бы пойти и посмотреть, как Эрик Липперт объясняет их (если вы готовы к тому, что ваш ум взорван, но в Python это может выглядеть немного так:
def attempt(operation, continuation):
try:
operation()
except:
log('operation failed!')
continuation()
внутри вашего цикла, вы могли бы сделать:
attempt(attempt_something, lambda: foo(bar)) # attempt_something is a function
думаю, что вы сопоставляете 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 )]
вы можете использовать этот:
for l in loop:
attempt() and foo(bar)
но вы должны убедиться, что attempt () возвращает True или False.
на самом деле, однако, ответ Johnsyweb, вероятно, лучше.
обычно я не публикую второй ответ, но это альтернативный подход, если вам действительно не нравится мой первый ответ.
помните, что функция может возвращать 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 и все такое.
помимо контекста я просто хочу ответить на вопрос вкратце. Нет, функция не может быть!--1--> цикл он может быть вызван. Это потому, что у него нет информации об этом контексте. Кроме того, это вызовет целый новый класс вопросов, например, что произойдет, если эта функция будет вызвана без окружающего цикла для обработки этого continue
?
но функция может сигнал различными способами, что он хочет абоненту continue
любой цикл в настоящее время выполняет. Одним из средств, конечно, является возвращаемое значение. Возвращение False
или None
сигнализировать об этом, например. Другой способ сигнализировать об этом-поднять специальный Exception
:
class ContinuePlease(Exception): pass
def f():
raise ContinuePlease()
for i in range(10):
try:
f()
except ContinuePlease:
continue
поместите цикл for вне try, кроме блока ... простой... ;-)
import sys if '3.4' in sys.version: from termcolor import coloreddef list_attributes(module_name): '''Import the module before calling this func on it.s ''' for index, method in enumerate(dir(module_name)): try: method = str(method) module = 'email' expression = module + '.' + method print('*' * len(expression), '\n') print( str(index).upper() + '. ',colored( expression.upper(), 'red'), ' ', eval( expression ).dir() , '...' , '\n'2 ) print('' * len(expression), '\n') print( eval( expression + '.doc' ), '\n'*4, 'END OF DESCRIPTION FOR: ' + expression.upper(), '\n'*4) except (AttributeError, NameError): continue else: pass finally: pass
Edit: удалил всю эту глупость, которую я сказал...
окончательный ответ состоял в том, чтобы переписать все это, так что мне не нужно так кодировать.