1

I have a function

 def f():
      while True:
           blah

I want to alter f in such a way that the caller could control the number of times the while loop in f runs, without altering much of the code in f (specially not adding a counter in f). Something like

 def f(num_executions = True):
      while num_executions:
           blah()

f() will run an infinite loop but f(an_expression_that_evaluates_to_true_n_times) will run the while loop n times. What could such an expression be?

UPDATE: I know, there are plenty of way to control how many times a loop will run, but the real question here is -

Can an expression in python evaluate to True for configurable number of times?

Some ideas I am toying with

-making an expression out of list = list[:-1]

-modifying default parameters of a function within a function

zonked.zonda
  • 347
  • 1
  • 5
  • 19
  • 2
    Why not use a for-loop? – TerryA May 23 '13 at 22:00
  • num_exeuctions shouldn't be a boolean. Use a for-loop – César May 23 '13 at 22:01
  • I agree with @Haidro, use a for loop. –  May 23 '13 at 22:01
  • I'm not understanding your latter question. In fact, you shouldn't really be asking two different questions :p. – TerryA May 23 '13 at 22:07
  • 2
    `itertools.repeat(True, n)` is a Python expression that evaluates to `True` `n` times. – kojiro May 23 '13 at 22:12
  • @kojiro Only if you iterate over it, not if you just call `bool()` on it. – Gareth Latty May 23 '13 at 22:21
  • @Lattyware are there programming languages that have iterables you don't have to iterate over? – kojiro May 23 '13 at 23:57
  • @kojiro No, but as my answer shows, there is a solution to the problem the OP asks about - yours doesn't help. – Gareth Latty May 24 '13 at 11:37
  • @Lattyware I don't understand why you say mine doesn't help. I gave one comment that shows an expression that evaluates to `True` `n` times if you iterate over it, and one answer that shows a way to control the number of times an infinite loop is actually iterated. And both of those answers violate the POLA less than yours. – kojiro May 24 '13 at 13:09
  • @kojiro The OP explained that he knew how to make a loop iterate `n` times, and that it was just an over-simplified example. – Gareth Latty May 24 '13 at 13:29
  • @Lattyware That doesn't explain why my answer is unhelpful. – kojiro May 24 '13 at 13:50

6 Answers6

5

No need for a while-loop. Use a for-loop:

>>> def f(n):
...     for _ in range(n):
...         dostuff()

_ is used as a variable name in a for loop normally to be a placeholder. This loop loops through n amount of times. So f(5) would loop five times.

TerryA
  • 58,805
  • 11
  • 114
  • 143
3

While I agree with the others that this is a bad idea, it is entirely (and easily) possible:

class BoolChange:
    def __init__(self):
        self.count = 0

    def __bool__(self):
        self.count += 1
        return self.count <= 5

x = BoolChange()
while x:
    print("Running")

This outputs Running five times, then exits.

The main reason this is a bad idea is that it means checking the state of the object modifies it, which is weird behaviour people won't expect. I can't imagine a good use case for this.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • I think I can imagine (rare) use case : when you use some 3rd party code you don't want to touch, and you want to count times that the loop runs. In other words, the client might theoretically have some use for this. The loop code itself does not. – Elazar May 23 '13 at 22:20
2

You can't do exactly what you describe. What is passed in python is not an expression, but a value. An object. An Immutable object in general evaluate to either True or to False. It will not change during the loop. Mutable object can change its truth value, but you can't make arbitrary object change during a general loop (which does not touch it in any way). In general, as have been said here, you really need to use for statement, or pass in a callable object (say, a function):

def f(is_true = lambda x : True):
    while is_true():
        blah()

Note that the reason that the callable solution is acceptable, while the "hiding in boolean" @Lattyware demonstrated is not, is that the additional coputation here is explicit - the () tells the reader that almost anything can happen here, depending on the object passed, and you don't need to know that the __bool__ method in this object is silently called and is expected to have side effect.

Elazar
  • 20,415
  • 4
  • 46
  • 67
0
def f(c=-1):
    while c:
        print 'blah'
        if c > 0: c -= 1
perreal
  • 94,503
  • 21
  • 155
  • 181
0

How about using a generator as a coroutine?

def blah():
    print 'hi'

def f():
    while True:
        blah()
        yield

x = f()
next(x) # "hi"

The generator here isn't be used for what it yields, but you get to control how many times it blahs externally, because it yields control ever time it blahs.

for i in range(3):
    next(x) # blah blah blah
kojiro
  • 74,557
  • 19
  • 143
  • 201
0

This will also work -

def foo(n=[1,2,3]):
     foo.func_defaults = tuple([foo.func_defaults[0][:-1]],)
     return n

while foo():
    blah()
zonked.zonda
  • 347
  • 1
  • 5
  • 19