Discussion:
while loop - multiple condition
Shiva
2014-10-12 17:08:00 UTC
Permalink
Why is the second part of while condition not being checked?

while ans.lower() != 'yes' or ans.lower()[0] != 'y':
ans = input('Do you like python?')


My intention is if either of the conditions are true the loop should break.
But the condition after 'or' doesn't seem to evaluate.

Thanks,
Shiva.
Chris Angelico
2014-10-12 17:13:04 UTC
Permalink
On Mon, Oct 13, 2014 at 4:08 AM, Shiva
Post by Shiva
Why is the second part of while condition not being checked?
ans = input('Do you like python?')
My intention is if either of the conditions are true the loop should break.
But the condition after 'or' doesn't seem to evaluate.
The loop will continue while either part is true - that's what "or"
means. Is that what you intended it to be doing?

ChrisA
Shiva
2014-10-12 17:21:02 UTC
Permalink
Post by Chris Angelico
The loop will continue while either part is true - that's what "or"
means. Is that what you intended it to be doing?
ChrisA
Yes......however, the second part of the or condition doesn't get evaluated.
So if I enter a 'y' - I expect the second part to evaluate and the loop to
break - but that doesn't seem to happen.
Chris Angelico
2014-10-12 17:31:47 UTC
Permalink
On Mon, Oct 13, 2014 at 4:21 AM, Shiva
Post by Shiva
Post by Chris Angelico
The loop will continue while either part is true - that's what "or"
means. Is that what you intended it to be doing?
ChrisA
Yes......however, the second part of the or condition doesn't get evaluated.
So if I enter a 'y' - I expect the second part to evaluate and the loop to
break - but that doesn't seem to happen.
Break it down into separate parts and have a look at what's happening.

while ans.lower() != 'yes' or ans.lower()[0] != 'y':
ans = input('Do you like python?')
print("ans.lower() = {!r}; first cond = {!r}, second cond {!r},
disjunction {!r}".format(
ans.lower(), (ans.lower() != 'yes'), (ans.lower()[0] != 'y'),
(ans.lower() != 'yes' or ans.lower()[0] != 'y')
))

The while loop will continue so long as the disjunction is True. See
what it's actually doing.

This is fundamental Boolean logic, a basic skill of programming.
You're going to need to master this. Look at the different pieces, and
get your head around what the 'or' operator actually does.

ChrisA
Shiva
2014-10-12 17:59:25 UTC
Permalink
Bit confusing to use in While loop - Should have used the 'and' condition
instead of OR- then it works fine.
for OR both condition need to be false to produce a false output and break
the loop.
More of SET operations.

Thanks,
Shiva
Chris Angelico
2014-10-12 18:03:31 UTC
Permalink
On Mon, Oct 13, 2014 at 4:59 AM, Shiva
Post by Shiva
Bit confusing to use in While loop - Should have used the 'and' condition
instead of OR- then it works fine.
for OR both condition need to be false to produce a false output and break
the loop.
Correct, what you're looking for here is indeed an 'and' (also called
a conjunction, as opposed to the disjunction of 'or'). Both operators
are important; and you need to understand what they do so you know
when to use each.

ChrisA
Marko Rauhamaa
2014-10-12 19:16:56 UTC
Permalink
Post by Chris Angelico
On Mon, Oct 13, 2014 at 4:59 AM, Shiva
Post by Shiva
Bit confusing to use in While loop - Should have used the 'and' condition
instead of OR- then it works fine.
for OR both condition need to be false to produce a false output and break
the loop.
Correct, what you're looking for here is indeed an 'and' (also called
a conjunction, as opposed to the disjunction of 'or'). Both operators
are important; and you need to understand what they do so you know
when to use each.
The corrected version

while ans.lower() != 'yes' and ans.lower()[0] != 'y':
ans = input('Do you like python?')

is equivalent with

while ans.lower()[0] != 'y':
ans = input('Do you like python?')


Marko
Chris Angelico
2014-10-12 19:22:24 UTC
Permalink
Post by Marko Rauhamaa
The corrected version
ans = input('Do you like python?')
is equivalent with
It's true that the first part is redundant, but trimming that out
wouldn't have taught the OP about boolean logic :)

ChrisA
Tim Chase
2014-10-12 20:42:35 UTC
Permalink
Post by Marko Rauhamaa
is equivalent with
ans = input('Do you like python?')
And still better improved with

while ans[:1].lower() != 'y':
ans = input('Do you like python?')

in the event that len(ans)==0 (a situation which will crash the
various current examples).

It also only expends the effort to lowercase 0-or-1 characters,
rather than lowercasing an entire string just to throw away
everything except the first character.

-tkc
Steven D'Aprano
2014-10-12 22:56:02 UTC
Permalink
Post by Tim Chase
Post by Marko Rauhamaa
is equivalent with
ans = input('Do you like python?')
And still better improved with
ans = input('Do you like python?')
The intention is to loop forever until the victim breaks down and accepts
that they like Python, by entering "yes" or "y". I'm pretty sure that
entering "yellow" or "you've got to be kidding" should not break the loop.

When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.

When checking for equality against multiple values, instead of:

x == a or x == b or x == c

it is usually easier to use `in`:

x in (a, b, c)


So we have:

# loop so long as the victim answers "yes" or "y"
while ans.lower() in ('yes', 'y'):
ans = input('Do you like python? Well, do you?')

# loop until the victim answers "yes" or "y"
while not (ans.lower() in ('yes', 'y')):
ans = input('Do you like python? Well, do you?')


both of which work fine if the user stays mum by entering the empty string.

You can also write:

while ans.lower() not in ('yes', 'y'):
ans = input('Do you like python? Well, do you?')


if you prefer. In my opinion, that's the most readable version of all.

One last note: if you are using Python 3.3 or better, you can support
international text better by using the casefold() method rather than
lower(). In this case, it won't make a difference, but the technically
correct method for doing case-insensitive comparisons is to casefold both
strings rather than lower- or upper-case them.
--
Steven
Rob Gaddi
2014-10-13 16:12:48 UTC
Permalink
On Mon, 13 Oct 2014 09:56:02 +1100
Post by Steven D'Aprano
When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.
I was just explaining this concept to a young pup the other day. De
Morgan's lets you say that (not (p and q)) == ((not p) or (not q)), but
the positive logic flavor is substantially less error-prone. People
are fundamentally not as good at thinking about inverted logic.
--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.
Rustom Mody
2014-10-13 16:26:57 UTC
Permalink
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:56:02 +1100
Post by Steven D'Aprano
When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.
I was just explaining this concept to a young pup the other day. De
Morgan's lets you say that (not (p and q)) == ((not p) or (not q)), but
the positive logic flavor is substantially less error-prone. People
are fundamentally not as good at thinking about inverted logic.
Curious: Which of

- (not (p and q))
- ((not p) or (not q))

is more positive (less negative)??
Rob Gaddi
2014-10-13 16:43:08 UTC
Permalink
On Mon, 13 Oct 2014 09:26:57 -0700 (PDT)
Post by Rustom Mody
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:56:02 +1100
Post by Steven D'Aprano
When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.
I was just explaining this concept to a young pup the other day. De
Morgan's lets you say that (not (p and q)) == ((not p) or (not q)), but
the positive logic flavor is substantially less error-prone. People
are fundamentally not as good at thinking about inverted logic.
Curious: Which of
- (not (p and q))
- ((not p) or (not q))
is more positive (less negative)??
The first is asking you to compare positive conditions (p and q) and
negate the entire thing (NAND). The second asks you to think about
the combination of two different "not true" pieces of logic
(OR of two inverted inputs). The first is pretty straightforward, and
I usually see people get it right. The second gets screwed up as often
as not.

And of course, any combination of ands and ors should be broken into
multiple statements with a descriptive variable name in the middle or
all hope is lost.
--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.
Rustom Mody
2014-10-13 17:12:13 UTC
Permalink
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:26:57 -0700 (PDT)
Post by Rustom Mody
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:56:02 +1100
Post by Steven D'Aprano
When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.
I was just explaining this concept to a young pup the other day. De
Morgan's lets you say that (not (p and q)) == ((not p) or (not q)), but
the positive logic flavor is substantially less error-prone. People
are fundamentally not as good at thinking about inverted logic.
Curious: Which of
- (not (p and q))
- ((not p) or (not q))
is more positive (less negative)??
The first is asking you to compare positive conditions (p and q) and
negate the entire thing (NAND). The second asks you to think about
the combination of two different "not true" pieces of logic
(OR of two inverted inputs). The first is pretty straightforward, and
I usually see people get it right. The second gets screwed up as often
as not.
And of course, any combination of ands and ors should be broken into
multiple statements with a descriptive variable name in the middle or
all hope is lost.
Yeah I guess 2 nots is one more than one!

However (to my eyes)
while i < N and a[i] != X:

looks less negative than

while not (i==N or a[i] == X):

[Of course i < N is not identical to i != N ]
Michael Torrie
2014-10-13 22:08:36 UTC
Permalink
Post by Rustom Mody
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:26:57 -0700 (PDT)
Post by Rustom Mody
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:56:02 +1100
Post by Steven D'Aprano
When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.
I was just explaining this concept to a young pup the other day. De
Morgan's lets you say that (not (p and q)) == ((not p) or (not q)), but
the positive logic flavor is substantially less error-prone. People
are fundamentally not as good at thinking about inverted logic.
Curious: Which of
- (not (p and q))
- ((not p) or (not q))
is more positive (less negative)??
The first is asking you to compare positive conditions (p and q) and
negate the entire thing (NAND). The second asks you to think about
the combination of two different "not true" pieces of logic
(OR of two inverted inputs). The first is pretty straightforward, and
I usually see people get it right. The second gets screwed up as often
as not.
And of course, any combination of ands and ors should be broken into
multiple statements with a descriptive variable name in the middle or
all hope is lost.
Yeah I guess 2 nots is one more than one!
However (to my eyes)
looks less negative than
[Of course i < N is not identical to i != N ]
Right it should have been not (i >= N or a[i] == X) to be equivalent.

In assembler it's often best to reverse the condition and then use the
opposite jump mnemonic. IE, if the test is to see if a number not zero,
use the jump if zero command instead. Often it reduces the number of
jumps required and eliminates the need to jump over the body of the "if"
block.

if a != 0 then jump to bigger
jump to end
bigger:
blah
blah
end:

vs

if a == 0 then jump to end
blah
blah
end:
wxjmfauth
2014-10-14 06:34:54 UTC
Permalink
Post by Michael Torrie
Post by Rustom Mody
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:26:57 -0700 (PDT)
Post by Rustom Mody
Post by Rob Gaddi
On Mon, 13 Oct 2014 09:56:02 +1100
Post by Steven D'Aprano
When you have multiple clauses in the condition, it's easier to reason about
them if you write the clauses as positive statements rather than negative
statements, that is, "something is true" rather than "something is not
true", and then use `not` to reverse it if you want to loop *until* the
overall condition is true.
I was just explaining this concept to a young pup the other day. De
Morgan's lets you say that (not (p and q)) == ((not p) or (not q)), but
the positive logic flavor is substantially less error-prone. People
are fundamentally not as good at thinking about inverted logic.
Curious: Which of
- (not (p and q))
- ((not p) or (not q))
is more positive (less negative)??
The first is asking you to compare positive conditions (p and q) and
negate the entire thing (NAND). The second asks you to think about
the combination of two different "not true" pieces of logic
(OR of two inverted inputs). The first is pretty straightforward, and
I usually see people get it right. The second gets screwed up as often
as not.
And of course, any combination of ands and ors should be broken into
multiple statements with a descriptive variable name in the middle or
all hope is lost.
Yeah I guess 2 nots is one more than one!
However (to my eyes)
looks less negative than
[Of course i < N is not identical to i != N ]
Right it should have been not (i >= N or a[i] == X) to be equivalent.
In assembler it's often best to reverse the condition and then use the
opposite jump mnemonic. IE, if the test is to see if a number not zero,
use the jump if zero command instead. Often it reduces the number of
jumps required and eliminates the need to jump over the body of the "if"
block.
if a != 0 then jump to bigger
jump to end
blah
blah
vs
if a == 0 then jump to end
blah
blah
On the side of logic.
Nothing can beat this mathematical absurdity (in the
logical sense of the term) called Flexible String
Representation.

Simply unbelievable.

jmf
giacomo boffi
2014-10-14 23:04:42 UTC
Permalink
Post by Tim Chase
Post by Marko Rauhamaa
is equivalent with
ans = input('Do you like python?')
And still better improved with
ans = input('Do you like python?')
yok is Turkish for an EMPHATIC NO
(or, at least, that's what I was led to think many years ago)
Chris Angelico
2014-10-14 23:16:58 UTC
Permalink
Post by giacomo boffi
Post by Tim Chase
Post by Marko Rauhamaa
is equivalent with
ans = input('Do you like python?')
And still better improved with
ans = input('Do you like python?')
yok is Turkish for an EMPHATIC NO
(or, at least, that's what I was led to think many years ago)
Corrupted core, are you ready to start the procedure?
What do you think?
Interpreting vague answer as: Yes!

If your program misinterprets a non-English response to an English
question, that's not critical. It just means you haven't implemented
full i18n. :)

ChrisA

Roy Smith
2014-10-12 17:28:35 UTC
Permalink
In article <mailman.14792.1413133694.18130.python-list at python.org>,
Post by Shiva
Why is the second part of while condition not being checked?
ans = input('Do you like python?')
My intention is if either of the conditions are true the loop should break.
But the condition after 'or' doesn't seem to evaluate.
A general rule of programming (be it Python or any other language) is to
break up complicated code into smaller pieces which can be understood
and tested in isolation. Your 'while' condition is kind of hairy.
There's a couple of complicated expressions, a logical conjuction, and
two different negated comparisons. That's a lot to understand all at
once.

I would factor that out into a little function:

-------------------------------------------------------
def is_yes(answer):
if answer.lower() == 'yes':
return True
if answer.lower()[0] == 'y':
return True
return False

while is_yes(ans):
ans = input('Do you like python?')
-------------------------------------------------------

Now, you can play around with your is_yes() function in an interactive
session and see what it returns for various inputs, in isolation from
the rest of your program:

print is_yes('y')
print is_yes('yes')
print is_yes('no')
print is_yes('you bet your sweet bippy')
Denis McMahon
2014-10-12 19:35:35 UTC
Permalink
while ans.lower() is not equal to "yes"
or ans.lower()[0] is not equal to "y"

the loop will continue to run

Note that if ans.lower() == 'y', then the first clause ( ans.lower() !=
'yes' ) is true, so the loop will continue to run, ignoring the result of
the second clause ( ans.lower()[0] != 'y' ), This will also be the case
if you reverse the order of the clauses.

It seems that you need a better understanding of combinatorial logic,
perhaps http://www.ee.surrey.ac.uk/Projects/Labview/boolalgebra/
index.html#booleantheorems will help.
--
Denis McMahon, denismfmcmahon at gmail.com
Chris Angelico
2014-10-13 00:51:02 UTC
Permalink
On Mon, Oct 13, 2014 at 11:43 AM, Dennis Lee Bieber
ONE: Python uses short circuit evaluation: for an OR, the second clause
is only looked at if the first clause is FALSE (for an AND, the first
clause has to be TRUE before the second is evaluated).
Short-circuiting doesn't actually matter here, incidentally. It could
be eagerly evaluated and nothing would be different.

ChrisA
Gelonida N
2014-10-13 08:31:56 UTC
Permalink
Post by Shiva
ans = input('Do you like python?')
I personally consider double negations less intuitive than following:


while not( ans.lower() == 'yes' and ans.lower()[0] == 'y' ):

Reading this line yoy would have noticed as wellm that what you really
wanted would have been:

while not( ans.lower() == 'yes' or ans.lower()[0] == 'y' ):



I would write the coder differently.

With your code you have to pre-initialze the variable ans.


I personally consider it also more 'intuitive' / easier to understand if
I can see the break conditiion. to many nots / != / negations can be
confusing as you noticed yourself.

Taking into account the Steven's suggestion about using the 'in'
expression it could be:


while True:
ans = input('Do you like python?')
if ans.lower() in ('yes', 'y'):
break
Chris Angelico
2014-10-13 11:59:00 UTC
Permalink
Taking into account the Steven's suggestion about using the 'in' expression
ans = input('Do you like python?')
break
Or, even simpler: Use an active condition.

while input('Do you like python?') not in ('yes', 'y'): pass

ChrisA
Skip Montanaro
2014-10-13 12:10:09 UTC
Permalink
Post by Chris Angelico
while input('Do you like python?') not in ('yes', 'y'): pass
Unfortunately, you probably have to account for people who SHOUT:

while input('Do you like python?').lower() not in ('yes', 'y'): pass

<wink>

Skip
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20141013/fab1ec0d/attachment.html>
Chris Angelico
2014-10-13 13:46:53 UTC
Permalink
On Mon, Oct 13, 2014 at 11:10 PM, Skip Montanaro
Post by Skip Montanaro
Post by Chris Angelico
while input('Do you like python?') not in ('yes', 'y'): pass
while input('Do you like python?').lower() not in ('yes', 'y'): pass
<wink>
Welcome to collaborative editing. I make a change and introduce a bug.
Fortunately, someone else can, just like that, fix that bug. Thanks!
:)

ChrisA
Marko Rauhamaa
2014-10-13 12:09:19 UTC
Permalink
Post by Chris Angelico
Or, even simpler: Use an active condition.
while input('Do you like python?') not in ('yes', 'y'): pass
Instead of the traditional "pull" technology, you could take advantage
of the state-of-the-art "push" approach:

print("You must love python -- everybody does!")


Marko
Chris Angelico
2014-10-13 13:48:25 UTC
Permalink
Post by Marko Rauhamaa
Post by Chris Angelico
Or, even simpler: Use an active condition.
while input('Do you like python?') not in ('yes', 'y'): pass
Instead of the traditional "pull" technology, you could take advantage
print("You must love python -- everybody does!")
Nay, there is love in excess. I thank heaven there are many pythons in
England; but if thou lovest them all, I withdraw my thanks!
-- Colonel Fairfax

ChrisA
Continue reading on narkive:
Loading...