While loop with 2 conditions problem

Hello, I’m new to python and code in general. I’m trying to create a quiz game as my first project. Because of this, I’m adding a bunch of other things like adding your name for the game to call you throughout the session. I also ask the gender so the game knows wether to call you mr/mrs.
my code looks something like this:

> print('Please enter your gender.')
> gender = input().lower()
> 
> 
> 
> if gender == 'male':
>     print('Nice to meet you Mr.', last_name, '!')
>     main_menu()
> if gender == 'female':
>     print('Nice to meet you Ms.', last_name, '!')
>     main_menu()
> 
> 
> def gen_error():
>     print("I'm sorry,I did not understand that.)
>     print('Enter "MALE" for male or "FEMALE" for female.')
> 
> 
> while gender != ('male' or 'female'):
>     gen_error()
>     gender_input = input().lower()
>     if gender_input == 'female':
>         break

This is the only way that i have gotten it to work close to how i want it but the problem is, when i type in ‘female’, it still calls the “gen_error” message. Just wondering if anyone knows a way to fix this or an easier way to do it altogether. Thanks!

You have to breakdown that condition in the while loop to see what it’s doing.

So in your repl do this

x = "male" or "female"
gender = "male"
print(gender != x)
gender = "female"
print(gender != x)

Notice x is always going to be "male". This is because or when used in this context will assign the first truthy object to x. str is a subclass of collections.Sequence whose __bool__ implementation defers to __len__ for deciding if True or False should be returned. So a sequence of length 0 returns False and a sequence of non zero length returns True.

let’s see demonstrate some other examples

print("" or "male")
print("male" or "")
print("female" or "male")

From the python docs

https://docs.python.org/3/reference/expressions.html#boolean-operations

Now to provide you with a solution

!= does not distribute over or in python, as I believe I demonstrated above. What you must do is split that into a disjunction of not equal operations or more concisely using a generator expression or even more concisely using a containment check

gender != "male" and gender != "female"
not any(gender == x for x in ("male", "female"))
gender not in {"male", "female"}

2 Likes

FYI, gender != "male" or gender != "female" is always True. What you mean is gender != "male" and gender != "female".

2 Likes

Dummy me! Completely forgot DeMorgan’s

Thank you! But I’ll be completely honest, the first time I ever touched python or anything to do with code at all was 2 days ago. So while I understand some functions and how some things work, that explanation went over my head. Thank you for trying though. :joy:

I understand the part about returning with a zero or non zero and that’s why I figured it didn’t work but I don’t understand at the end when you give the solution

A suggestion for part of your code:

salutations = {'male': 'Mr.', 'female': 'Ms.', 'other': 'M.'}
gender = input(f"Enter one of ({', '.join(salutations)}): ")

I will try to explain it.

Before the statement below is encountered the variable gender has been assigned the text entered by user.

while gender != ('male' or 'female'):
    ...

The part gender != ('male' or 'female') is an expression which is evaluated as True or False.

Let’s analyze the expression. Like in mathematics first the expression inside parentheses has to be evaluated:
'male' or 'female'
The operator or is a boolean operator. It evaluates its operands as truthy or falsy. Here the operands are strings which are falsy when empty. Otherwise they are truthy. So here both operands are regarded as True.

>>> bool('')
False
>>> bool('male')
True

The operator or has one more property - it performs shortcut evaluation. It means when the result is known from the first operand, the second one is not evaluated. This is our case - the first operand is truthy so the result must be truthy regardless the second operand.

…but or has yet one more property. The result of the operation is the last operand evaluated. So in our case the result is 'male' (the second operand 'female' did not need to be evaluated):

>>> 'male' or 'female'
'male'

Let’s substitute the result for the expression’s part in parentheses:

gender != 'male'

Now I think you understand what the expression does. When you are in doubts I recommend you to deconstruct your expression to pieces and evaluate the pieces separately.

1 Like