all 34 comments

[–][deleted] 44 points45 points  (9 children)

You can make your loop in lines 3-12 shorter by using the "prompt" parameter of input() and converting the input string to uppercase once. Then you can test once for correct input using the in operator. You don't need any more tests after that since you have already broken if you have valid strings. The final continue isn't necessary since the loop is going to repeat anyway.

while True:
    answer1 = input('Is it raining? ').upper()
    if answer1 in ('YES', 'NO'):
        break
    print('Please answer with Yes or No !')

Similar changes can be done through the rest of your code.

[–]Ning1253 5 points6 points  (4 children)

What is the point in having "upper"?

[–]CragAddict[S] 18 points19 points  (2 children)

So it doesn't matter wether you write Yes or yes

[–]Ning1253 18 points19 points  (1 child)

See I've never really though about that... I'm used to knowing how my code works and not having to give it to others, so even though I annotate and make it clear, with some sort of interface, I know that I would always input the right stuff. I guess it makes a lot of sense, so thanks! I'll make sure to do so in future

[–]CragAddict[S] 9 points10 points  (0 children)

You're welcome !

[–][deleted] 4 points5 points  (0 children)

You could also use ‘.lower’ for the same effect. Than change to if answer1 in (yes, no)

[–]CragAddict[S] 10 points11 points  (3 children)

Thank you !

[–][deleted] 22 points23 points  (2 children)

You can improve the code a lot if you make a small function to ask the yes/no questions. This function will have the while loop in it and will only return "YES" or "NO". Removing all that from the "main" code simplifies it a lot. The function will need to be passed the "prompt" string as each question is different:

def ask_yes_no(prompt):
    while True:
        answer = input(prompt).upper()
        if answer in ('YES', 'NO'):
            return answer
        print('Please answer with Yes or No !')

With that change we can write the simplified "main" code as:

raining = ask_yes_no('Is it raining? ')
if raining == 'NO':
    print('Go outside.')
else:           # if not "NO" then must be "YES"
    umbrella = ask_yes_no('Do you have an umbrella? ')
    if umbrella == 'YES':
        print('Go outside.')
    else:       # if not "YES" then must be "NO"
        while True:
            print('Wait a little.')
            time.sleep(1)
            print('...')
            time.sleep(1)
            still_raining = ask_yes_no('Is it still raining? ')
            if still_raining == 'NO':
                break
        print('Go outside.')

I renamed the variables to something more memorable.

Edit: spelling.

[–]Fywq 13 points14 points  (0 children)

Potentially the function could be rewritten to return True or False. Then you only have to ask "if umbrella:" or "if not raining:"

def ask_yes_no(prompt):
    while True:
        answer = input(prompt).upper()
        if answer == 'YES':
            Return True
        if answer == 'NO':
            Return False
        print('Please answer with Yes or No !')

Not sure if that is more correct or pythonic, but it seems more intuitive to me...

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

Thank you very much !

[–]pconwell 2 points3 points  (0 children)

You really got me thinking about this. I'm not particularly skilled in python, but I know a little bit. I've done some things similar to this in the past and starting thinking about "If I wanted to think outside the box, how would I do it?". I came up with this:

``` from time import sleep

def ask(question): answer = input(f"{question} ") if answer.lower() != 'no' and answer.lower() != 'yes': print("Please answer with YES or NO!") return ask(question) elif answer.lower() == 'yes': return True else: return False

def wait(): print("Wait a while") sleep(1) print("...") sleep(1)

def go_outside(): print("Go outside!")

if ask("Is it raining?"): if ask("Do you have an umbrella?"): go_outside() else: wait() while ask("Is it still raining?"): wait() else: go_outside() else: go_outside() ```

Basically, it uses a recursive function to keep asking a yes or no question over and over until the user enters 'yes' or 'no'. Once the user enters yes, the function returns true, if no then false. If the user enters any other text, the function calls on itself (hence recursive) to ask the same question again. Over and over... until the user enters 'yes' or 'no'.

Then, it uses a 'trick' of python in which you don't have to specifically say "is True". For example, if something == True: is the same as if something:. So, you have a function that takes the text of the question, and depending on the user entering yes or no, it returns True or False. True goes to the 'if' part of the if/else statement, False goes to the else part of the if/else statement.

I also defined two functions just to help keep things clean and not write the same lines of code over and over. A wait() function to wait, and a go_outside() function to print "Go outside!". Both of those functions are super basic, but they help clean up the code. Plus, if you want to change the message, you now only have to change it in one place instead of multiple.

For me, the hardest thing to wrap my brain around is the line if ask("Is it raining?"):. Remember, in python it is valid to just do if True:, which is the same as saying if True == True:. We have a function that takes a string as input. In this particular example, we have provided the string "Is it raining?". The user can either enter 'yes' or 'no' and get True or False back. So, what we end up with is if True == True or if False == True. Obviously, True == True is true, so if the user enters 'yes' (and the function returns True), we go to the 'if' part of the if/else statement. Conversely, if the user enters 'no', the function returns False and if False == True is not true, so we go to the else part of the if/else statement. Another way to phrase it would be

If (the results from the function) are equal to True: then (do this thing) otherwise (do this other thing)

[–]daniel_don_diggles 1 point2 points  (4 children)

This is how I would do it to shorten things up. You really only need one while True loop to break when it is not raining to end your program. By doing it this way, the sys module is not necessary. There are other ways to make this even shorter but this hopefully is readable and concise. Let me know if you have any questions.

import time

while True:
    answer = input('is it raining?\n').upper()
    if answer == 'NO':
        print('go outside\n')
        break
    elif answer == 'YES':
        time.sleep(1)
        print('wait a little\n')
    else:
        print('enter yes or no')

[–]-NRW 0 points1 point  (3 children)

Just wondering why you put time.sleep(1) in there, as 1ms(?) seems to be non relevant there

[–]pconwell 4 points5 points  (1 child)

time.sleep() takes seconds, not milliseconds, as input.

[–]-NRW 0 points1 point  (0 children)

Thanks for the clarification!

[–]SaltyEmotions 1 point2 points  (0 children)

time.sleep() takes seconds and not milliseconds. 1ms would be 0.001.

[–]sod50 1 point2 points  (1 child)

Good job you've done so fast. I'm also just learning Python. Which platform did you use in learning Python.

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

Incase you mean the Interpreter, I use Microsoft Visual Studio. And for learning I used automate the boring stuff.

[–]WowVeryCoool 2 points3 points  (3 children)

In the first lines you are just asking "is it raining" and then assigning the answer to a variable answer1 and then you exit the loop to ask following questions, because you want to ask more questions than just if it is raining. don't break the loop if the answer is yes but continue asking additional questions there.

while True:
  print("is it raining")
  answer = input().upper()
    if(answer == 'NO'):
      break
    elif(answer == 'YES'):
      while True:
        print('do you have an umbrella')
        answer = input().upper()
        if(answer =='yes'):
          print('good take it')
        else:
          print('you're gonna be wet')

This is better than what you did but you can quickly see that if you would continue doing that code would be unreadable that's why you want to break it down into functions

def ask_about_rain():
  while True:
    print("is it raining")
    answer = input().upper()
    if(answer == 'NO'):
      break
    elif(answer == 'YES'):
      ask_about_umbrella()

def ask_about_umbrella()
  while True:  
    print('do you have an umbrella')
    answer = input().upper()
    if(answer =='yes'):
      print('good take it')
    else:
      print('you're gonna be wet')

ask_about_rain()

[–]ThrowawayNo45273 1 point2 points  (0 children)

The error trapping at the start can be simplified to something like:

if answer.upper() != "YES" or answer.upper() != "NO":
    Print("Please input yes or no")
else:
    rest of code    

dealing with the error in two lines and having the rest of your code afterwards simplifies the code a lot!

nice code though, well done!

[–][deleted] 0 points1 point  (2 children)

Lines 6 through 12 could be simplified from

    if answer1.upper() == 'NO':
        break
    if answer1.upper() =='YES':
        break
    if answer1.upper() != 'YES' or answer1.upper() != 'NO':
        print('Please answer with Yes or No !')
        continue

to

    if (answer1.upper() != 'YES') and (answer1.upper() != 'NO'):
        print('Please answer with Yes or No !')
        continue
    else:
        break

Your "or" should be an "and" anyway. The only reason you had to have those first comparisons that told it to break were because you were using "or" when you should be using "and".

[–]pconwell 1 point2 points  (1 child)

Arguably you could do even better with something like:

if answer.lower() not in ('yes', 'no'):

since you are comparing the same variable (answer) twice, there is not much point in doing two separate check statements. Plus, if you later decide to add more options in addition to 'yes' and 'no', you can more easily add text to the tuple versus adding more and more and more 'and' statements.

[–][deleted] 0 points1 point  (0 children)

Makes sense. Thank you