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.