2

So I have for example the following while statements and I would like to combine them. Because this can get tiresome if you have 20 of these with all different if statements.

while True:
    name = str(raw_input("NAME PLEASE\n"))
    if name.isalpha():
        break
    print("Please chars dude")

while True:
    age = raw_input("Please type your age\n")
    if age.isdigit():
        break
    print("Please digits only")

If I combine them and someone types a A-Z character with 'age' then the code restarts all over without having saved the 'name' statement. I would like it to save 'name' if it's correct and only start over from the if statement that was false.

while True:
    name = str(raw_input("NAME PLEASE\n"))
    if name.isalpha():
        break
    print("Please chars dude")

    age = raw_input("Please type your age\n")
    if age.isdigit():
        break
    print("Please digits only")
0

7 Answers 7

4

Use a function to encapsulate asking for information. You can pass in a validation test function:

def ask(question, validator, errormessage):
    while True:
        result = raw_input(question)
        if not validator(result):
            print(errormessage)
            continue
        return result


name = ask("NAME PLEASE\n", lambda s: s.isalpha(), "Please chars dude")
age = ask("Please type your age\n", lambda s: s.isdigit(), "Please digits only")

This is far more readable then any number of tests to see if the user already entered a correct name and you only need to ask for the age now.

Sign up to request clarification or add additional context in comments.

8 Comments

lambda s: s.isalpha() ? why not str.isalpha ?
Martijn, I thought of doing this as it is basically the same as writing multiple while statements, but I was just wondering whether a while statement could be combined like I asked. But, if no one else has the answer then this will be the preferable answer indeed. Thank you.
@Jean-FrançoisFabre: in principle, yes. But I'd only do that if you need to optimise a tight loop. I think this is a little easier to follow.
understanding lambda is not easy for a lot of people. Ok matter of taste.
@Vinny: str.isalpha is the unbound method on the str type. str.isalpha('foobar') gives you the exact same results as 'foobar'.isalpha(), because str.isalpha is bound to the 'foobar' str instance.
|
3

Why not use functions and cut down on some duplication in the process?

def ask_input(prompt, error_msg, validation_fn):
    while True:
        data = raw_input(prompt)
        if validation_fn(data):
            return data
        print(error_msg)

name = ask_input("NAME PLEASE\n", "Please chars dude", lambda x: x.isalpha())
age = ask_input("Please type your age\n", "Please digits only",
                lambda x: x.isdigit())

In this case, the prompt (what to ask the user), an error message (what to provide on invalid input), and a validation function are provided to the ask_input() function. This hides the while loop behind the function call and gives you something more meaningful to read in the code.

The lambda functions are just an easy way to help do the validation. You could do this instead:

def isalpha(x):
    return x.isalpha()


def isdigit(x):
    return x.isdigit()

name = ask_input("NAME PLEASE\n", "Please chars dude", isalpha)
age = ask_input("Please type your age\n", "Please digits only", isdigit)

Comments

1

You can set the variables to None first, and then check them before assignment:

name, age = None, None

while True:
    if name is None:
        name = str(raw_input("NAME PLEASE\n"))
        if not name.isalpha():
            print("Please chars dude")
            name = None
            continue

    if age is None:
        age = raw_input("Please type your age\n")
        if not age.isdigit():
            print("Please digits only")
            age = None
            continue

    print("input is valid")
    break

continue will start the loop over again. This fits better in the logic of your code, since break actually stop and exit the loop code.

Comments

0

Just use flags to track weather valid input is given, if given then exit the loop.

name_input_required = True
name = ''
while name_input_required:
    name = str(raw_input("NAME PLEASE\n"))
    if name.isalpha():
        name_input_required = False
    else:
        print("Please chars dude")

age_input_required = True
age = None
while age_input_required:
    age = raw_input("Please type your age\n")
    if age.isdigit():
        age_input_required = False
    else:
        print("Please digits only")

3 Comments

Now you just used two while statements and made it less pythonic
Not that you should use a flag variable. Just use while True: and break.
I thought of that, but then I also need two different functions right? One for the isdigit() and one for the isalpha() check
0

Try this:

name = None
age = None

while requires_info:
    if name is None:
        temp_name = str(raw_input("NAME PLEASE\n"))
        if temp_name.isalpha():
            name = temp_name
            continue
        else:
            print("Please chars dude")
            continue
    if age is None:
        temp_age = raw_input("Please type your age\n")
        if temp_age.isdigit():
            age = temp_age
            continue
        else:
            print("Please digits only")
            continue
    break

What we do here is use a single continuous loop and a few if statements/variables to track what still needs to be done. Note depending on how you want them to enter the data you may also add logic to not ask for age if the name was invalid.

Comments

0

So I have for example the following while statements and I would like to combine them. Because this can get tiresome if you have 20 of these with all different if statements.

I assume the actual problem is "How to reduce tiresome code?" instead of "How to merge two loops into one?". I think keeping two loops is a good idea.

def safe_input(prompt, err_message, validation_fn):
    while True:
        value = raw_input(prompt)
        if validation_fn(value):
            return value
        print err_message

name = safe_input("NAME PLEASE\n", "Please chars dude", str.isalpha)
age = safe_input("Please type your age\n", "Please digits only", str.isdigit)

If you always want the used to enter text in a separate line, you might want to print prompt before raw_input and to not give an argument to raw_input. That way you don't have to supply "\n" in every call of safe_input.

Comments

0

Yes, you can combine both loops in one loop!

Always try to solve the problem line by line.
You will get to learn the language better and it is the most simple way to solve any problem too.

A line by line solution would look like this:

name = ''  # define name outside while loop
while True:
    if not name:
        name = str(raw_input("NAME PLEASE\n"))
        if not name.isalpha():  # validate name
            print("Please chars dude")
            # reset name
            name = ''

    else:
        age = raw_input("Please type your age\n")
        if age.isdigit():  # validate age
            """continue your code here"""
            print('name: ' + name + ' and age: ' + age)
            print('Ok! Goodbye!')
            break  # while loop
        else:
            print("Please digits only")

will print:

NAME PLEASE
Elis
Please type your age
30
name: Elis and age: 30
Ok! Goodbye!

This will help you understand while loop better and how to use it in more difficult cases.

Do not over design using redundant language features. It will make refactoring and debugging difficult.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.