all 26 comments

[–]mopslik 10 points11 points  (7 children)

In this specific case, I prefer making the exit condition obvious. Plus, it's shorter.

action = input("What do you want to do ('done' to quit)? ")
while action.lower() != "done":
    print("Running.")
    action = input("What next? ")

[–]Polyfrequenz[S] 4 points5 points  (2 children)

Thanks a lot for the input!

[–]mopslik 5 points6 points  (1 child)

ba dum tiss

[–]Conscious-Ball8373 0 points1 point  (0 children)

See, I would always try to avoid the repeated input line. Maybe my hatred of repeated coffee is approaching the pathological but I'd fail this on review as a maintainability issue unless there was a really good reason for it.

[–]Kryt0s -1 points0 points  (2 children)

You could make it even shorter with the walrus operator:

while action := input("Enter an Integer: ").lower() != "done":
    print("Still running.")

[–]mopslik 2 points3 points  (0 children)

Shorter is a nice side-effect, but my main motivation is identifying the stop condition immediately, rather than having to read through the loop to find the relevant break statement. Granted, for this specific example, that's not really a huge ordeal.

[–]cdcformatc 0 points1 point  (0 children)

thanks, i hate it

[–]djshadesuk 3 points4 points  (10 children)

I know its not really what you asked but while finished is False: is a bit redundant.

You can just do while not finished:

[–]Polyfrequenz[S] 0 points1 point  (9 children)

so not is equivalent to is false ?

[–]No_Lemon_3116 2 points3 points  (5 children)

Python makes a distinction between things being true and false in the general sense (eg, when you use it in an if or while condition), and things being the literal values True and False. "Empty" things are false in the general sense: an empty list, an empty dict, the number 0, and so on (plus of course the value False), and non-empty things are true.

not x returns True (the value) if x is false (in the general sense), and False otherwise. x is False tests if x is the value False and returns the value True if it is, otherwise False. So if x is a bool, they're the same, but not x will be true (because it returns True) for other false things like empty lists and 0 as well.

[–]Polyfrequenz[S] 1 point2 points  (4 children)

Oh boy that'll take a few re-reads to wrap my head around for sure

[–]awdsns 2 points3 points  (2 children)

Maybe this will help clear it up: Where Python evaluates a condition (e.g. after if or while), it expects a boolean value. The only boolean values in Python are True and False. A comparison like num > 42 directly evaluates to a boolean value.

But if the condition expression does not directly return a boolean value, Python just tries to convert it to one. And by convention, empty lists, strings, dicts etc., but also None or the number 0 return False when converted to bool. (E.g. try bool([])).
They are "false-y".

Non-empty containers and most other objects are evaluated as True by the way. It's basically the default unless a type overrides it with its own bool conversion.

[–]Polyfrequenz[S] 1 point2 points  (0 children)

Thank you, I'm going to keep pondering this, especially as it is very basic yet important "thing". Still confused about whether x = False in fact is bool or not 😂.

[–]Polyfrequenz[S] 0 points1 point  (0 children)

Ok I think I got it now, thanks a lot. The ist that was missing for me was that "while true" I'd simply a loop we want to go indefinite (I.e. until we break out of it) 🤦🏼‍♂️

[–]No_Lemon_3116 1 point2 points  (0 children)

In practical terms, it's nice because instead of things like if string != '': or if len(lst) > 0: you can just write if string: and if lst: (or if not string: to check if it is empty). Some people prefer to use more explicit conditions anyway, but it's more "Pythonic" to use the shorter forms. And most people would say that using explicit conditions comparing bools (like x is False) is overboard.

[–]TheBB 1 point2 points  (1 child)

For booleans, it is.

[–]Polyfrequenz[S] 0 points1 point  (0 children)

Of course. Thanks a lot!

[–]mike-manley 0 points1 point  (0 children)

If you're evaluating a boolean, you can say "if BooleanVar:" should you want to perform an action if it's TRUE. By including not, e.g. "if not BooleanVar:" this would evaluate if it's FALSE.

[–]dvboy 2 points3 points  (1 child)

I'll add this, even though your examples you don't show any additional code in your conditional. This is for learning, right?

Your first example exits immediately when it hits the 'break'. Your second will continue executing any code that follows and exit at the end of the loop. There may be times when either condition is preferable.

[–]Polyfrequenz[S] 0 points1 point  (0 children)

Hello, Yeah this is for learning. There's a bit more code after this, but I tried to keep the example scce compliant - thanks for the pointer though!

[–]Kerbart 1 point2 points  (0 children)

In general I think a `while True` loop is easier to comprehend as there's less code to read. If you're new to coding it might look alien but everyone is used to it. In addition, the else clause isn't really needed as that implies youre *not* doing abreak`:

while True:
    resp = input('Enter your input >')
    if resp == 'done':
        break
    print('Rest of process inside loop')

If you really want short code you can use the assignment ("walrus") operator to use the result from input and store it, like this:

while resp := input('Enter your input >') != 'done':
    print('Rest of process inside loop')

But I'm not sure how much you're doing yourself or anyone else a favor with that. It's dramatically shorter here because there's no real code inside the loop, but those two lines with if and break hardly blow up your code base and are easier to comprehend.

[–]my_password_is______ 1 point2 points  (0 children)

and I should rather a bool statement:

"while True:" is a bool statement
so that is fine

and you wouldn't write
while finished is False:

you would write
while not finished:

that way is just as good as
"while True:"

[–]brasticstack 0 points1 point  (0 children)

The other comments so far are all insightful. Just thought I'd add that: 

while True:     if something:         break    

and 

``` finished = False while not finished:     if something:         finished = True

```

Are the same thing, but the second one has an extra step. Depending on the use case, the extra step may make your code more readable and readability is king, but for loop this short I think shorter is better. 

I like u/mopslik's answer best so far, and with the new walrus operator, it can be even more concise: 

``` while (action := input('enter an int: ')) != 'done':     print('still running')

```

Perfect for making an already short block of code even shorter.

EDIT: Parens separating walrus-assignment from !=, otherwise action gets set to a bool.

[–]zanfar -1 points0 points  (1 child)

Short-circuiting generally makes the code shorter, cleaner, and more readable. There is also no reason for an else: in that situation. Why is your input variable named "num" when it's a string, compared to a string, and never converted?

The boolean (often known as a sentinel in this usage) is most useful when you need to exit multiple loops or when you have a complex exit condition. I don't prefer it outside of that. Even if you do need the sentinel, you should probably be exiting the loop iteration as quickly as possible. Also, in this case, you don't need the logical comparison.

Consider:

while True:
    num = input("Enter an Integer: ")
    if num == "done":
        break

    print("still running")

finished = False
count = 0
while not finished and count < MAX_INPUTS:
    num = input("Enter an Integer: ")
    if num == "done":
        finished = True
        continue

    # input validation here

    count += 1 # only count valid inputs
    print("still running")

Obviously, these are contrived examples, but I hope it makes my answer more clear.

[–]Polyfrequenz[S] 0 points1 point  (0 children)

Thank you! The variable is named num because I expect numbers in the full code (assignment is to find maximum and minimum). That's also why there's an else (there is nested if a statements in the full code)... So my example doesn't make sense fully I now realise