로 시작하는 루프가 for i in range(0, 100)
있습니다. 일반적으로 올바르게 실행되지만 네트워크 상태로 인해 실패하는 경우가 있습니다. 현재 나는 실패 continue
했을 때 except 절 에 있도록 설정했습니다 (에 대한 다음 숫자로 계속 i
).
동일한 번호를 다시 할당 i
하고 실패한 루프 반복을 다시 실행할 수 있습니까?
로 시작하는 루프가 for i in range(0, 100)
있습니다. 일반적으로 올바르게 실행되지만 네트워크 상태로 인해 실패하는 경우가 있습니다. 현재 나는 실패 continue
했을 때 except 절 에 있도록 설정했습니다 (에 대한 다음 숫자로 계속 i
).
동일한 번호를 다시 할당 i
하고 실패한 루프 반복을 다시 실행할 수 있습니까?
답변:
를 수행 while True
루프를 들어, 넣어 당신의 내부에 try
그에서 코드 내부 및 휴식 while
코드가 성공에만 루프.
for i in range(0,100):
while True:
try:
# do stuff
except SomeSpecificException:
continue
break
continue
시도 while
루프는 물론, 하지 는 for
, 너무 (!) i
되어 있지 "다음"아무것도 - 그것은 같은 이전 (실패) 다리에 있던 정확히 동일합니다 while
물론,.
재시도 횟수를 제한하여 특정 항목에 문제가있는 경우 다음 항목으로 계속 진행할 수 있습니다.
for i in range(100):
for attempt in range(10):
try:
# do thing
except:
# perhaps reconnect, etc.
else:
break
else:
# we failed all the attempts - deal with the consequences.
else:
절을 완벽하게 사용합니다 for
.
else
절은 try
당신이 찾고있는 "성공하면 깨짐"을합니다.
except
절 안에 "if 시도 = 9 : 발생"과 같은 것이 필요하고 10이 아닌 9를 사용해야
다시 시도 패키지는 실패 코드 블록을 재 시도 할 수있는 좋은 방법입니다.
예를 들면 다음과 같습니다.
@retry(wait_random_min=1000, wait_random_max=2000)
def wait_random_1_to_2_s():
print("Randomly wait 1 to 2 seconds between retries")
여기에 다른 솔루션과 유사한 솔루션이 있지만 규정 된 수 또는 재 시도에서 성공하지 못하면 예외가 발생합니다.
tries = 3
for i in range(tries):
try:
do_the_thing()
except KeyError as e:
if i < tries - 1: # i is zero indexed
continue
else:
raise
break
retries
이 잘못되었습니다. 오히려되어야 tries
합니다.
추악한 while 루프를 사용하지 않는보다 "기능적인"접근 방식 :
def tryAgain(retries=0):
if retries > 10: return
try:
# Do stuff
except:
retries+=1
tryAgain(retries)
tryAgain()
except: tryAgain(retries+1)
가장 명확한 방법은 명시 적으로 설정하는 것 i
입니다. 예를 들면 다음과 같습니다.
i = 0
while i < 100:
i += 1
try:
# do stuff
except MyException:
continue
i += 1
직후에 넣을 수도 있습니다 # do stuff
.
range
이런 종류의 물건에 사용해야합니다 .
시간 초과가있는 일반적인 솔루션 :
import time
def onerror_retry(exception, callback, timeout=2, timedelta=.1):
end_time = time.time() + timeout
while True:
try:
yield callback()
break
except exception:
if time.time() > end_time:
raise
elif timedelta > 0:
time.sleep(timedelta)
용법:
for retry in onerror_retry(SomeSpecificException, do_stuff):
retry()
except exception:
try … except
사용할 수 있습니다 if
. 그러나 그것은 덜 파이썬입니다.
callback
함수는 결코 호출되지 않습니다. 괄호를 잊어 버렸습니다 callback()
.
for _ in range(5):
try:
# replace this with something that may fail
raise ValueError("foo")
# replace Exception with a more specific exception
except Exception as e:
err = e
continue
# no exception, continue remainder of code
else:
break
# did not break the for loop, therefore all attempts
# raised an exception
else:
raise err
내 버전은 위의 몇 가지와 비슷하지만 별도의 while
루프를 사용하지 않으며 모든 재 시도에 실패하면 최신 예외를 다시 발생시킵니다. 명시 적으로 err = None
상단에 설정할 수 는 있지만 else
오류가 발생 하여 최종 블록을 설정 해야하기 때문에 반드시 최종 블록을 실행해야하므로 엄격하게 필요하지는 않습니다 err
.
Python Decorator Library 와 비슷한 것이 있습니다 .
예외를 테스트하지 않고 반환 값을 명심하십시오. 데코 레이팅 된 함수가 True를 반환 할 때까지 재 시도합니다.
약간 수정 된 버전이 트릭을 수행해야합니다.
retrying
: tenacity
및 backoff
(2020 업데이트)에 대한 대안재 시도 라이브러리는 이전에가는 방법,하지만 슬프게도 그것은 몇 가지 버그를 가지고 있으며, 2016 년 다른 대안이 될 것으로 보인다 이후이 업데이트이 없어 백 오프 와 끈기 . 이 글을 쓰는 동안 강인성은 더 많은 GItHub 별 (2.3k 대 1.2k)을 가지고 있으며 더 최근에 업데이트되었으므로 사용하기로 결정했습니다. 예를 들면 다음과 같습니다.
from functools import partial
import random # producing random errors for this example
from tenacity import retry, stop_after_delay, wait_fixed, retry_if_exception_type
# Custom error type for this example
class CommunicationError(Exception):
pass
# Define shorthand decorator for the used settings.
retry_on_communication_error = partial(
retry,
stop=stop_after_delay(10), # max. 10 seconds wait.
wait=wait_fixed(0.4), # wait 400ms
retry=retry_if_exception_type(CommunicationError),
)()
@retry_on_communication_error
def do_something_unreliable(i):
if random.randint(1, 5) == 3:
print('Run#', i, 'Error occured. Retrying.')
raise CommunicationError()
위의 코드는 다음과 같이 출력됩니다.
Run# 3 Error occured. Retrying.
Run# 5 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 10 Error occured. Retrying.
.
.
.
에 대한 자세한 설정 tenacity.retry
은 tenacity GitHub 페이지에 나와 있습니다.
중첩 루프가없는 솔루션을 원하고 break
성공을 불러 retriable
일으키는 경우 반복 가능한 빠른 랩핑 을 개발할 수 있습니다. 다음은 자주 실행되는 네트워킹 문제의 예입니다. 저장된 인증이 만료됩니다. 그것을 사용하면 다음과 같이 읽습니다.
client = get_client()
smart_loop = retriable(list_of_values):
for value in smart_loop:
try:
client.do_something_with(value)
except ClientAuthExpired:
client = get_client()
smart_loop.retry()
continue
except NetworkTimeout:
smart_loop.retry()
continue
다음은이 문제에 대한 설명입니다. 다음 retry
기능은 다음 기능을 지원합니다.
import time
def retry(func, ex_type=Exception, limit=0, wait_ms=100, wait_increase_ratio=2, logger=None):
attempt = 1
while True:
try:
return func()
except Exception as ex:
if not isinstance(ex, ex_type):
raise ex
if 0 < limit <= attempt:
if logger:
logger.warning("no more attempts")
raise ex
if logger:
logger.error("failed execution attempt #%d", attempt, exc_info=ex)
attempt += 1
if logger:
logger.info("waiting %d ms before attempt #%d", wait_ms, attempt)
time.sleep(wait_ms / 1000)
wait_ms *= wait_increase_ratio
용법:
def fail_randomly():
y = random.randint(0, 10)
if y < 10:
y = 0
return x / y
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler(stream=sys.stdout))
logger.info("starting")
result = retry.retry(fail_randomly, ex_type=ZeroDivisionError, limit=20, logger=logger)
logger.info("result is: %s", result)
자세한 내용은 내 게시물 을 참조하십시오.
이 문제를 해결하는 방법에 대한 내 아이디어는 다음과 같습니다.
j = 19
def calc(y):
global j
try:
j = j + 8 - y
x = int(y/j) # this will eventually raise DIV/0 when j=0
print("i = ", str(y), " j = ", str(j), " x = ", str(x))
except:
j = j + 1 # when the exception happens, increment "j" and retry
calc(y)
for i in range(50):
calc(i)
나는 최근 에이 문제에 대한 해결책으로 파이썬과 함께 일했으며 스택 오버 플로우 방문자와 공유하게되어 기쁘다면 피드백을 보내주십시오.
print("\nmonthly salary per day and year converter".title())
print('==' * 25)
def income_counter(day, salary, month):
global result2, result, is_ready, result3
result = salary / month
result2 = result * day
result3 = salary * 12
is_ready = True
return result, result2, result3, is_ready
i = 0
for i in range(5):
try:
month = int(input("\ntotal days of the current month: "))
salary = int(input("total salary per month: "))
day = int(input("Total Days to calculate> "))
income_counter(day=day, salary=salary, month=month)
if is_ready:
print(f'Your Salary per one day is: {round(result)}')
print(f'your income in {day} days will be: {round(result2)}')
print(f'your total income in one year will be: {round(result3)}')
break
else:
continue
except ZeroDivisionError:
is_ready = False
i += 1
print("a month does'nt have 0 days, please try again")
print(f'total chances left: {5 - i}')
except ValueError:
is_ready = False
i += 1
print("Invalid value, please type a number")
print(f'total chances left: {5 - i}')
try 절이 성공할 때만 루프 변수를 증가시킵니다.
range(100)
첫 번째 매개 변수없이 사용할 수 있습니다 . Python 2.x를 사용하면조차 사용할 수 있습니다xrange(100)
. 이것은 반복자를 생성하고 더 적은 메모리를 사용합니다. (100 개체에만 중요하지는 않습니다.)