More elegant way to try running a function X times?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Gilles Ganault

    More elegant way to try running a function X times?

    Hello

    As a newbie, it's pretty likely that there's a smarter way to do this,
    so I'd like to check with the experts:

    I need to try calling a function 5 times. If successful, move on; If
    not, print an error message, and exit the program:

    =====
    success = None

    for i in range(5):
    #Try to fetch public IP
    success = CheckIP()
    if success:
    break

    if not success:
    print "Exiting."
    sys.exit()
    =====

    Thank you.
  • Tim Chase

    #2
    Re: More elegant way to try running a function X times?

    I need to try calling a function 5 times. If successful, move on; If
    not, print an error message, and exit the program:
    >
    success = None
    for i in range(5):
    #Try to fetch public IP
    success = CheckIP()
    if success:
    break
    if not success:
    print "Exiting."
    sys.exit()
    Though a bit of an abuse, you can use

    if not any(CheckIP() for _ in range(5)):
    print "Exiting"
    sys.exit()

    (this assumes Python2.5, but the any() function is easily
    recreated per the docs at [1]; and also assumes the generator
    creation of 2.4, so this isn't as useful in 2.3 and below)

    Alternatively, you can use the for/else structure:

    for i in range(5):
    if CheckIP():
    break
    else:
    print "Exiting"
    sys.exit()

    -tkc

    [1]






    ..

    Comment

    • Sion Arrowsmith

      #3
      Re: More elegant way to try running a function X times?

      Gilles Ganault <nospam@nospam. comwrote:
      >As a newbie, it's pretty likely that there's a smarter way to do this,
      >so I'd like to check with the experts:
      >
      >I need to try calling a function 5 times. If successful, move on; If
      >not, print an error message, and exit the program:
      >
      >=====
      >success = None
      >
      >for i in range(5):
      > #Try to fetch public IP
      > success = CheckIP()
      > if success:
      > break
      >
      >if not success:
      > print "Exiting."
      > sys.exit()
      >=====
      for i in range(5):
      if CheckIP():
      break
      else:
      print "Exiting."
      sys.exit()

      Note very carefully that the "else" goes with the "for" and not the "if".

      --
      \S -- siona@chiark.gr eenend.org.uk -- http://www.chaos.org.uk/~sion/
      "Frankly I have no feelings towards penguins one way or the other"
      -- Arthur C. Clarke
      her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

      Comment

      • Nicholas Ferenc Fabry

        #4
        Re: More elegant way to try running a function X times?


        On Nov 19, 2008, at 09:09, Gilles Ganault wrote:
        Hello
        >
        As a newbie, it's pretty likely that there's a smarter way to do this,
        so I'd like to check with the experts:
        >
        I need to try calling a function 5 times. If successful, move on; If
        not, print an error message, and exit the program:
        >
        =====
        success = None
        >
        for i in range(5):
        #Try to fetch public IP
        success = CheckIP()
        if success:
        break
        >
        if not success:
        print "Exiting."
        sys.exit()
        =====
        >
        A little simpler:

        for i in range(5):
        if CheckIP():
        break
        else:
        print "Exiting."
        sys.exit()

        The else part will only fire if the for finishes without breaking.
        Hope this helps a bit...


        Nick Fabry









        Comment

        • Gilles Ganault

          #5
          Re: More elegant way to try running a function X times?

          On 19 Nov 2008 14:37:06 +0000 (GMT), Sion Arrowsmith
          <siona@chiark.g reenend.org.ukw rote:
          >Note very carefully that the "else" goes with the "for" and not the "if".
          Thanks guys.

          Comment

          • George Sakkis

            #6
            Re: More elegant way to try running a function X times?

            On Nov 19, 10:21 am, Gilles Ganault <nos...@nospam. comwrote:
            On 19 Nov 2008 14:37:06 +0000 (GMT), Sion Arrowsmith
            >
            <si...@chiark.g reenend.org.ukw rote:
            Note very carefully that the "else" goes with the "for" and not the "if"..
            >
            Thanks guys.
            And if you end up doing this for several different functions, you can
            factor it out with the following decorator:

            class MaxRetriesExcee dedError(Except ion):
            pass

            def retry(n):
            def decorator(f):
            def wrapper(*args, **kwds):
            for i in xrange(n):
            r = f(*args, **kwds)
            if r: return r
            raise MaxRetriesExcee dedError
            return wrapper
            return decorator

            If the number of retries is fixed and known at "compile" time, you can
            use the standard decorator syntax:

            @retry(5)
            def CheckIP():
            ...

            If not, just decorate it explicitly at runtime:

            def CheckIP():
            ...

            n = int(raw_input(' Give number of retries:'))
            CheckIP = retry(n)(CheckI P)


            HTH,
            George

            Comment

            • Boris Borcic

              #7
              Re: More elegant way to try running a function X times?

              Tim Chase wrote:
              >success = None
              >for i in range(5):
              > #Try to fetch public IP
              > success = CheckIP()
              > if success:
              > break
              >if not success:
              > print "Exiting."
              > sys.exit()
              >
              Though a bit of an abuse, you can use
              >
              if not any(CheckIP() for _ in range(5)):
              print "Exiting"
              sys.exit()
              I don't see why you speak of abuse, bit of abuse would be, say if you replaced
              range(5) by '12345' to win a char; but otoh I think you misspelled any() for all().

              Cheers BB

              Comment

              • Tim Chase

                #8
                Re: More elegant way to try running a function X times?

                >>success = None
                >>for i in range(5):
                >> #Try to fetch public IP
                >> success = CheckIP()
                >> if success:
                >> break
                >>if not success:
                >> print "Exiting."
                >> sys.exit()
                >Though a bit of an abuse, you can use
                >>
                > if not any(CheckIP() for _ in range(5)):
                > print "Exiting"
                > sys.exit()
                >
                I don't see why you speak of abuse, bit of abuse would be, say if you replaced
                range(5) by '12345' to win a char; but otoh I think you misspelled any() for all().
                The OP's code break'ed (broke?) upon the first success, rather
                than checking all of them. Thus, it would be any() rather than
                all(). Using all() would require 5 successful calls to
                CheckIP(), rather than one-out-of-five successful calls.

                As for abuse, the "for _ in iterable" always feels a little hokey
                to me. It works, but feels warty.

                -tkc



                Comment

                • Steve Holden

                  #9
                  Re: More elegant way to try running a function X times?

                  Gilles Ganault wrote:
                  Hello
                  >
                  As a newbie, it's pretty likely that there's a smarter way to do this,
                  so I'd like to check with the experts:
                  >
                  I need to try calling a function 5 times. If successful, move on; If
                  not, print an error message, and exit the program:
                  >
                  =====
                  success = None
                  >
                  for i in range(5):
                  #Try to fetch public IP
                  success = CheckIP()
                  if success:
                  break
                  >
                  if not success:
                  print "Exiting."
                  sys.exit()
                  Use the for statement's "else" clause: it's there to allow you to
                  specify code to be executed only when the loop terminates normally.

                  for i in range(5):
                  if CheckIP():
                  break
                  else:
                  sys.exit("Could not verify IP address")
                  .... remainder of program ...

                  regards
                  Steve
                  --
                  Steve Holden +1 571 484 6266 +1 800 494 3119
                  Holden Web LLC http://www.holdenweb.com/

                  Comment

                  • Boris Borcic

                    #10
                    Re: More elegant way to try running a function X times?

                    Tim Chase wrote:
                    >>>success = None
                    >>>for i in range(5):
                    >>> #Try to fetch public IP
                    >>> success = CheckIP()
                    >>> if success:
                    >>> break
                    >>>if not success:
                    >>> print "Exiting."
                    >>> sys.exit()
                    >>Though a bit of an abuse, you can use
                    >>>
                    >> if not any(CheckIP() for _ in range(5)):
                    >> print "Exiting"
                    >> sys.exit()
                    >>
                    >I don't see why you speak of abuse, bit of abuse would be, say if you
                    >replaced range(5) by '12345' to win a char; but otoh I think you
                    >misspelled any() for all().
                    >
                    The OP's code break'ed (broke?) upon the first success, rather than
                    checking all of them. Thus, it would be any() rather than all(). Using
                    all() would require 5 successful calls to CheckIP(), rather than
                    one-out-of-five successful calls.
                    Right. So it could also be written " if all(not CheckIP()... ". Perhaps more
                    closely re-telling the OP's ?
                    >
                    As for abuse, the "for _ in iterable" always feels a little hokey to
                    me. It works, but feels warty.
                    I guess this means you did not learn Prolog before Python ?

                    Cheers, BB

                    Comment

                    Working...