-2

I was trying to make a simple program that asks for the sex of the user. And the only two inputs it accepts it is: "M" or "F".

Then:

sex = str(input('[ M / F ]: ')).upper().strip()

while sex != 'M' or sex != 'F':
     print('error')
     sex = str(input('try again [ M / F ]: ')).upper().strip()

print('It's done :)')

But it only works if i use the term "and" in the loop. It is not a big question but i really wanted to know why...

Arruda
  • 11
  • 1
  • 6
    Because every possible value of `sex` will *always* "not equal" at least one of `'M'` or `'F'`... – David Aug 04 '23 at 14:42
  • Please, **do not** use Markdown in source code. Use code comments. – tadman Aug 04 '23 at 14:42
  • 'I need someone who's not X and simultaneously also not Y". Neither X nor Y can be both itself and not itself. – tadman Aug 04 '23 at 14:43
  • 2
    `sex` can only hold one value at a time, so it is always not equal to `M` or not equal to `F`. If it is `F` it is not equal to `M` and if it is `M` it is not equal to `F`. Or it could be equal to neither of those, of course. The reason it works with `and` is that `and` is the correct conjunction to use here. – kindall Aug 04 '23 at 14:43
  • 1
    PSA: Test for "inclusion in list" versus this type of coding. `if sex in sexes`. – tadman Aug 04 '23 at 14:43
  • (1) "Is `sex` different from `'M'`?" (2) "Is `sex` different from `'F'`?" (3) Is the answer to either 1 or 2 "yes"? ... The answer to question 3 is always "yes", right? – slothrop Aug 04 '23 at 14:44
  • 2
    By the way, a better way to write this is `sex not in ('M', 'F')` which is a lot clearer. – kindall Aug 04 '23 at 14:44
  • 1
    Does this answer your question? [Python 'while' with two conditions: "and" or "or"](https://stackoverflow.com/questions/54163163/python-while-with-two-conditions-and-or-or) – SiHa Aug 04 '23 at 14:45

3 Answers3

4

For your while loop to break you need both conditions to be False, this would mean sex being both M and F at the same time.

This is never possible.

Corrected code:

sex = str(input('[ M / F ]: ')).upper().strip()

while sex != 'M' and sex != 'F':
    print('error')
    sex = str(input('try again [ M / F ]: ')).upper().strip()

print('It\'s done :)')

Or using De Morgan's equivalence:

sex = str(input('[ M / F ]: ')).upper().strip()

while not (sex == 'M' or sex == 'F'):
    print('error')
    sex = str(input('try again [ M / F ]: ')).upper().strip()

print('It\'s done :)')

Or the classical pythonic way:

sex = str(input('[ M / F ]: ')).upper().strip()

while sex not in {'F', 'M'}:
    print('error')
    sex = str(input('try again [ M / F ]: ')).upper().strip()

print('It\'s done :)')
mozway
  • 194,879
  • 13
  • 39
  • 75
  • For the pythonic way I most frequently see lists being used, not sets, and I would suggest doing that: a set has better *asymptotic* runtime, but it has a substantial constant overhead compared to a list, and is therefore no faster than lists for a small number of elements (indeed, it will be *slower*). – Konrad Rudolph Aug 04 '23 at 14:56
  • @KonradRudolph I agree that for two items a `tuple`/`list` is better, I just use sets out of habit and I don't think the difference here matters much (especially in a loop with user input) ;) – mozway Aug 04 '23 at 15:23
1

Let's put 3 cases into a truth table:

----------------------------------------------------------
sex  |  sex != 'M'  |  sex != 'F'  |           |  
     |       A      |       B      |   A or B  |  A and B
----------------------------------------------------------
X    |     True     |     True     |    True   |    True
M    |     False    |     True     |    True   |    False
F    |     True     |     False    |    True   |    False
----------------------------------------------------------

As you can see from the table, and is clearly the correct choice, while or always returns True.

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
1

You can reduce the amount of code and at the same time make it more robust as follows:

while (sex := input('[ M / F ]: ')).upper().strip() not in 'MF':
    print('error\ntry again ', end='')
# sex variable could be used here
print('It\'s done :)')

By using in rather than and or the erroneous or condition you will have simplified the process. Note also that input() returns str so the call to str() is irrelevant. It will work but it's unnecessary

DarkKnight
  • 19,739
  • 3
  • 6
  • 22