Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: do r = random_stuff() while not meets_condition(r)

I often have to randomly generate stuff with certain constraints. In many cases, it's quicker to ignore the constraints in generation, check if they are met afterwards and redo the process otherwise. Lacking a do keyword, I usually write

r = random_stuff()
while not meets_condition(r):
    r = random_stuff()

That's a bit ugly, as I have the same line of code twice. What I'd really like to have is a construct like

r = random_stuff() until meets_condition(r)

similar to the ternary operator introduced in 2.5:

a = b if condition else c

Just that here condition is evaluated before the left-hand side of the statement is executed. Does anybody have a suggestion for a design pattern (should work in Python 2.7) that remedies the while-constructs intrinsic unpythonic ugliness?

like image 274
Manuel Ebert Avatar asked May 08 '26 15:05

Manuel Ebert


2 Answers

while True:
    r = random_stuff()
    if meets_condition(r):
        break

or

condition = True
while condition:
    r = random_stuff()
    condition = not meets_condition(r)
like image 113
eumiro Avatar answered May 11 '26 05:05

eumiro


Your idea is not bad - but not with the new keyword until, but rather like

a = (<expression> while <condition>)

extending the idea of generator expressions.

As they don't exist, it won't help you.


But what you can use, is the iter function with the sentinel.

dummy_sentinel = object()
for r in iter(random_stuff, dummy_sentinel):
    if meets_condition(r): break

If you can be sure about your random_stuff() returning only a certain kind of values, such as numbers, strings, etc., you can take some other value as sentinel. Especially, when None never can occur, take this, in order to have a never-ending generator.

for r in iter(random_stuff, None):
    if meets_condition(r): break

Then random_stuff() gets called until it meets the condition.


Even better might be

r = next(r for r in iter(random_stuff, None) if meets_condition(r))

which gives you the first matching one.

like image 27
glglgl Avatar answered May 11 '26 05:05

glglgl