Search code examples
pythonpython-3.xlogiccycle

Simplest way of writing "while not the initial value"


If you want to do something while a variable foo != 5, having initial value 5 (for example) .

Does anyone know a cleaner way of doing this? One way is:

def try1():
    foo = 5
    aux = False
    while (foo != 5) or (aux == False):
        aux = True
        foo = (random.randint(1,100) // (foo +1)) +1
        print(foo)

Solution

  • If you're looking for a repeat-until structure, there isn't one in Python. But, you can get something similar by creating an iterator. You can then use that iterator in a for _ in ... statement to obtain the desired behaviour.

      def repeatUntil(condition):
          yield
          while not condition(): yield
    
      foo = 5
      for _ in repeatUntil(lambda:foo==5):
         foo = (random.randint(1,100) // (foo +1)) +1
         print(foo)
    

    Or repeatWhile() if you want to express the continuation condition instead of the stop condition. (in both cases, the condition will be tested at the end of the loop)

      def repeatWhile(condition):
          yield
          while condition(): yield
    
      foo = 5
      for _ in repeatWhile(lambda:foo!=5):
         foo = (random.randint(1,100) // (foo +1)) +1
         print(foo)
    

    Note that this approach will provide proper processing of continue where as while True: ... if foo==5: break would require extra code (and extra care).

    For example:

    foo = 5
    while True:
        foo = (random.randint(1,100) // (foo +1)) +1
        if someCondition == True: continue # loop will not stop even if foo == 5
        print(foo)
        if foo == 5: break
    

    [UPDATE] If you prefer using a while statement and don't want to have lambda: in the way, you could create a loopUntilTrue() function to manage forcing the first pass generically:

    def loopUntilTrue():  # used in while not loop(...):
        firstTime = [True]
        def loop(condition):
            return (not firstTime or firstTime.clear()) and condition
        return loop
    
    foo = 5
    reached = loopUntilTrue()
    while not reached(foo==5):    
        foo = (random.randint(1,100) // (foo +1)) +1
        print(foo)
    

    Note that you need to initialize a new instance of loopUntilTrue() for each while statement. This also implies that you will have to use different variable names (for reached) in nested while loops that use this approach

    You can do the same thing with an exit condition:

    def loopUntilFalse(): # used in while loop(...):
        firstTime = [True]
        def loop(condition):
            return (firstTime and not firstTime.clear()) or condition
        return loop
    
    foo = 5
    outcome = loopUntilFalse()
    while outcome(foo!=5):    
        foo = (random.randint(1,100) // (foo +1)) +1
        print(foo)