अपवाद के बाद पुन: प्रयास कैसे करें?


252

मैं एक पाश के साथ शुरू की है for i in range(0, 100)। आम तौर पर यह सही ढंग से चलता है, लेकिन कभी-कभी यह नेटवर्क की स्थिति के कारण विफल हो जाता है। वर्तमान में मैंने इसे सेट कर दिया है, ताकि विफलता पर, यह continueक्लॉज को छोड़कर (आगे के लिए अगले नंबर पर जारी रहे i)।

क्या iलूप की असफल पुनरावृत्ति के माध्यम से उसी संख्या को पुन: असाइन करना और चलाना संभव है ?


1
आप range(100)पहले पैरामीटर के बिना उपयोग कर सकते हैं । यदि आप पायथन 2.x का उपयोग करते हैं xrange(100), तो आप इसका उपयोग भी कर सकते हैं , यह एक पुनरावृत्ति उत्पन्न करता है और कम मेमोरी का उपयोग करता है। (ऐसा नहीं है कि यह केवल 100 वस्तुओं के साथ मायने रखता है।)
जॉर्ज शॉली


2
उस धागे में मध्यस्थता से निपटने के लिए समर्थन के साथ डेकोरेटर का उपयोग करते हुए एक बहुत ही सुंदर समाधान है
zitroneneis

जवाबों:


380

एक है while Trueअंदर अपने पाश के लिए, अपने डाल tryकि से कोड के अंदर है, और ब्रेक whileपाश केवल जब अपने कोड सफल होता है।

for i in range(0,100):
    while True:
        try:
            # do stuff
        except SomeSpecificException:
            continue
        break

31
@ इग्नासियो, हुह ? continueपुनर्प्रयास whileलूप, ज़ाहिर है, नहींfor है, तो (!) iहै नहीं "अगले" कुछ भी - यह बिल्कुल वैसा ही के रूप में यह पिछले एक (विफल) उसी के पैर पर थी whileज़ाहिर है,।
एलेक्स मार्टेली 6

13
जैसा कि xorsyst नोट करता है, वहां पर एक रिट्री लिमिट लगाने की सलाह दी जाती है। अन्यथा आप कुछ समय के लिए अटक सकते हैं।
ब्रैड कोच

2
यह एक उत्कृष्ट उदाहरण है: मध्यम.com
टोनी मेलोनी

7
मैं निश्चित रूप से जबकि ट्रू: लाइन को छोड़ दूंगा, अन्यथा ब्रेक विल्स बाहरी लूप को थकावट के लिए जारी रखता है।
Jan

1
@Sankalp, यह मुझे लगता है कि यह उत्तर प्रश्न पाठ के लिए उचित है।
zneak

189

मैं रिट्रीट की संख्या को सीमित करना पसंद करता हूं, ताकि अगर उस विशिष्ट आइटम के साथ कोई समस्या हो तो आप अंततः अगले एक पर जारी रखेंगे, इस प्रकार:

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.

3
@ g33kz0r के लिए पाइथन में निर्माण के लिए दूसरा क्लॉज निष्पादित होता है यदि लूप नहीं टूटता है। तो, इस मामले में, वह खंड निष्पादित होता है यदि हम सभी 10 प्रयास करते हैं और हमेशा एक अपवाद प्राप्त करते हैं।
xorsyst

7
यह एक महान जवाब है! वास्तव में बहुत अधिक उत्थान के हकदार हैं। यह पूरी तरह से पायथन में सभी सुविधाओं का उपयोग करता है, विशेष रूप से कम ज्ञात else:खंड for
पेपोलुआन

2
क्या आपको कोशिश के अंत में ब्रेक की आवश्यकता नहीं है: भाग? कोशिश में अतिरिक्त ब्रेक के साथ :, यदि प्रक्रिया सफलतापूर्वक पूरी होती है तो लूप टूट जाएगा, अगर यह सफलतापूर्वक पूरा नहीं होता है तो यह सीधे अपवाद वाले हिस्से में चला जाएगा। क्या इसका कोई मतलब है? अगर मैं कोशिश के अंत में एक विराम नहीं देता: यह सिर्फ 100 बार करता है।
ट्रिस्टन

1
@ ट्रिस्टन - इस का elseखंड try"अगर सफल है, तो टूट" जो आप ढूंढ रहे हैं।
पॉलएमसीजी

1
मैं फिर से प्रयास करने के लिए एक लूप पसंद करता हूं। इस कोड में एक शिकन यह है कि, यदि आप प्रयास करने पर अपवाद को फिर से उठाना चाहते हैं, तो आपको exceptक्लॉज़ के अंदर "
इफ़ेक्ट

69

पुन: प्रयास करने पैकेज विफलता पर कोड का एक खंड पुन: प्रयास करने के लिए एक अच्छा तरीका है।

उदाहरण के लिए:

@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")

4
अधिक आम तौर पर, जिप में रिटायर डेकोरेटर्स के लिए कई पैकेज होते हैं: pypi.python.org/…
kert

वैसे भी जब आप हर बार विफल हो जाते हैं तो आप कितने बार प्रयास कर सकते हैं?
dim_user

8
जैसा कि मुझे समझ में नहीं आया है, अधिक सक्रिय कांटा github.com/jd/tenacity है और शायद github.com/litl/backoff का भी उपयोग किया जा सकता है।
अलेक्सी श्रुब

23

यहां दूसरों के समान एक समाधान है, लेकिन यदि यह निर्धारित संख्या या रिट्रीट में सफल नहीं होता है तो यह अपवाद को बढ़ाएगा।

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
लुकास

सच @ लुकस। फिक्स्ड।
हर्क

बहुत अच्छा समाधान धन्यवाद। प्रत्येक कोशिश के बीच देरी जोड़कर इसमें सुधार किया जा सकता है। एपीआई के साथ काम करते समय बहुत उपयोगी है।
सैम

14

लूप्स के दौरान उन बदसूरत का उपयोग किए बिना "कार्यात्मक" दृष्टिकोण:

def tryAgain(retries=0):
    if retries > 10: return
    try:
        # Do stuff
    except:
        retries+=1
        tryAgain(retries)

tryAgain()

13
मुझे खेद है, लेकिन यह "बदसूरत जबकि छोरों" वेरिएंट की तुलना में बहुत कुरूप लगता है; और मैं फंक्शनल प्रोग्रामिंग का शौकीन हूं ...
लवेल्ला

9
आपको यह सुनिश्चित करने की आवश्यकता है कि आप गहराई से पुनरावृत्ति न करें - पाइथन में डिफ़ॉल्ट स्टैक का आकार 1000 है
Cal Paterson

5
यदि यह 'कार्यात्मक' होने जा रहा है, तो पुनरावृत्ति होनी चाहिए:except: tryAgain(retries+1)
quamrana

इसके साथ समस्या यह है कि हमें चर के रूप में त्रुटि पास करने की आवश्यकता है।
लोजहाओ

11

सबसे स्पष्ट तरीका स्पष्ट रूप से निर्धारित होगा i। उदाहरण के लिए:

i = 0
while i < 100:
    i += 1
    try:
        # do stuff

    except MyException:
        continue

37
वह C या C ++ है? मैं बता नहीं सकता।
जॉर्ज स्कोली 6

5
@Georg दैट पायथन, जैसा कि प्रश्न में कहा गया है। या जहां आप किसी कारण से व्यंग्यात्मक हैं?
जैकब बोर्ग

3
यह वह नहीं करता है जो ओपी ने मांगा था। यदि आप i += 1बस के बाद रख सकते हैं # do stuff
फेलिना

5
पायथोनिक नहीं है। rangeइस तरह के सामान के लिए उपयोग करना चाहिए ।
फकीर

2
मैं सहमत हूं, यह निश्चित रूप से रेंज का उपयोग करना चाहिए।
user2662833

5

टाइमआउट के साथ एक सामान्य समाधान:

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बयान का उपयोग कर सकते हैं । लेकिन यह कम पायथोनिक है।
लॉरेंट LAPORTE

यह समाधान काम नहीं करता है। trinket.io/python/caeead4f6b अपवाद do_stuff द्वारा फेंका जनरेटर के लिए बुलबुला नहीं है। यह, वैसे भी क्यों होगा? do_stuff को लूप के शरीर में कहा जाता है, जो अपने आप ही बाहरी स्तर पर होता है, जनरेटर में नेस्टेड नहीं होता है।
इसरांडी

आपका अधिकार, लेकिन एक अलग कारण के लिए: callbackफ़ंक्शन को कभी नहीं कहा जाता है। मैं कोष्ठक को भूल गया हूँ, द्वारा प्रतिस्थापित callback()
लॉरेंट LAPORTE

5
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सेट किया गया है।


4

पायथन डेकोरेटर लाइब्रेरी में भी कुछ ऐसा ही है ।

कृपया ध्यान रखें कि यह अपवादों के लिए परीक्षण नहीं करता है, लेकिन वापसी मूल्य। यह तब तक पीछे रहता है जब तक कि सजाए गए फ़ंक्शन सही नहीं हो जाते।

थोड़ा संशोधित संस्करण चाल करना चाहिए।


यहाँ कैसे अपवाद के लिए इसे संशोधित करने के लिए saltycrane.com/blog/2009/11/trying-out-retry-decorator-python
एंटनी Denyer

4

एक काउंटर का उपयोग करते हुए:

count = 1
while count <= 3:  # try 3 times
    try:
        # do_the_logic()
        break
    except SomeSpecificException as e:
        # If trying 3rd time and still error?? 
        # Just throw the error- we don't have anything to hide :)
        if count == 3:
            raise
        count += 1

4

पुनरावृत्ति का उपयोग करना

for i in range(100):
    def do():
        try:
            ## Network related scripts
        except SpecificException as ex:
            do()
    do() ## invoke do() whenever required inside this loop

1
शर्त से बाहर निकलें? या यह 100 * अनंत चलता है?
ingyhere

3

आप पायथन रिट्रींग पैकेज का उपयोग कर सकते हैं। पुनः प्रयास किया जाएगा

पायथन में लिखा गया है कि किसी भी चीज़ के लिए रिट्रीट व्यवहार को जोड़ने के कार्य को सरल बनाया जाए।


2

के विकल्प retrying: tenacityऔर backoff(2020 अद्यतन)

पुन: प्रयास पुस्तकालय पहले से जाने का रास्ता था, लेकिन दुर्भाग्य से यह कुछ कीड़े है और के बाद से 2016 तक अन्य विकल्प होने लगते हैं यह अपडेट नहीं मिला है backoff और दृढ़ता । इसे लिखने के समय, तप में अधिक 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.
.
.
.

के लिए अधिक सेटिंग्स तप GitHub पृष्ठtenacity.retry पर सूचीबद्ध हैं ।


1

यदि आप नेस्टेड छोरों के बिना एक समाधान चाहते हैं और 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

1

मैं अपने कोड में निम्नलिखित का उपयोग करता हूं,

   for i in range(0, 10):
    try:
        #things I need to do
    except ValueError:
        print("Try #{} failed with ValueError: Sleeping for 2 secs before next try:".format(i))
        time.sleep(2)
        continue
    break


0

यहां इस मुद्दे पर मेरी राय है। निम्नलिखित retryफ़ंक्शन निम्नलिखित विशेषताओं का समर्थन करता है:

  • सफल होने पर आह्वान किए गए फ़ंक्शन का मान लौटाता है
  • यदि थकावट समारोह के अपवाद को उठाता है, तो प्रयास समाप्त हो जाता है
  • प्रयासों की संख्या के लिए सीमा (असीमित के लिए 0)
  • प्रयासों के बीच प्रतीक्षा करें (रैखिक या घातीय)
  • केवल तभी अपवाद करें जब अपवाद विशिष्ट अपवाद प्रकार का उदाहरण हो।
  • प्रयासों का वैकल्पिक प्रवेश
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)

अधिक जानकारी के लिए मेरी पोस्ट देखें ।


-2

इसे ठीक करने के बारे में मेरा विचार यहाँ है:

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)

7
यह रास्ता बंद है।
क्रिस जॉनसन

-2

मैंने हाल ही में इस समस्या के समाधान पर अपने अजगर के साथ काम किया है और मुझे स्टैकओवरफ्लो आगंतुकों के साथ साझा करने में खुशी हो रही है, कृपया प्रतिक्रिया दें यदि यह आवश्यक है।

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}')

-9

अपना लूप वैरिएबल तभी बढ़ाएं जब कोशिश क्लॉज सफल हो जाए

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.