3
\$\begingroup\$

Can this Python code be written in a more Pythonic way?

'''
This scripts ask a user for the capital city of Peru, South America
'''

question = 'What is the capital city of Peru?'
answer = 'Lima'

# Ask question
print question

# Game continues as long as question is not answered
# Game ends after 3 failed attempts
end_game = False

# User has 2 attempts after entering the first wrong answer
attempts = 2

while end_game == False:
    # Get user answer
    user_answer = raw_input('Enter your answer: ').capitalize()

    # Validate users anser
    if user_answer == answer:
        print 'You got it right'
        end_game = True
    else:
        if attempts > 0:
            print 'Wrong! Try again. You have %d attempts left' %(attempts)
            attempts -= 1
        else:
            print 'You have no more attempts remaining'
            print 'The correct answer is %s' %(answer)
            print 'Oops!!! Game ended'
            end_game = True
\$\endgroup\$
  • \$\begingroup\$ your while loop looks unindented - and hence wrong. \$\endgroup\$ – Koby Becker Oct 11 '15 at 20:03
  • \$\begingroup\$ @KobyBecker, I added some indentation on the last if block, to validate question and save energy us all from all full to understand of closing, reposting and stuff... \$\endgroup\$ – holroy Oct 11 '15 at 20:57
7
\$\begingroup\$

It's kind of a limited code section, but let us go for a review ride:

  • Have everything enclosed in main() – The pythonic way of starting any code within a module is to have a main method called from the following if statement: if __name__ == '__main__':
  • Good naming of variables – You seem to name your variables good, that is in snake_case
  • Not so good while loop condition – Two slight errors here, first of all if using something like a flag it would have been better to do while not end_game instead of comparing against false. Even better would be to use your end of game indicator namely that there are no more attempts left: while attempts > 0: (or possibly while attempts_left:
  • Introducing elif – The combination of else: immediately followed by an if can often be better written as elif (which reads as else if something)
  • Introducing the improved print() – In Python 3 the print is going to change into a function to make it everything a little more coherent, and whilst changing that, one could also get used to the format string syntax. Which changes print 'answer is %s' %(answer) into print('answer is {}'.format(answer))
  • Make functions multipurpose – Often it is good to make a function multi-purpose, albeit still letting it have one primary concern. In your case this could be asking for capital cities

With all of these changes we got the code looking like:

'''
Ask user for what is the capital city of a given land
'''

import random

def ask_for_capital_city(land, capital_city, attempts_left = 3):
    """Ask for the capital city of a land with 3 attempts by default"""
    question = 'What is the capital city of {}?'.format(land)
    answer = capital_city

    # Ask question
    print(question)

    while attempts_left:
        # Get user answer
        user_answer = raw_input('Enter your answer: ').capitalize()

        # Validate users answer
        if user_answer == answer:
            print('You got it right')
            return True

        elif attempts_left:
            attempts_left -= 1
            print('Wrong! Try again. You have {} attempts left'.format(attempts_left))

        else:
            print('You have no more attempts remaining.')
            print('The correct answer is {}'.format(answer))
            print('Oops!!! Game ended')

    return False


def main():
    capital_cities = [
       ('Peru', 'Lima'),
       ('the UK', 'London'),
       ('the US', 'Washington DC'),
       ('Norway', 'Oslo'),
       ('Spain', 'Madrid'),
       ('Portugal', 'Lisbon'),
       ('Brazil', 'Brasilia'),
    ]

    # Your original code
    ask_for_capital_city('Peru', 'Lima')

    # Lets test for some more capital cities
    correct_answers = 0

    while ask_for_capital_city(*random.choice(capital_cities)):
        correct_answers += 1
        print('You got {} correct capital cities\n'.format(correct_answers))

    print('Goodbye!')


if __name__ == '__main__':
    main()

Do extend the list at will!

NB! When presenting code here at Code Review, the code is supposed to work, and in your case there was a little indentation fault. A good tip to avoid that is to paste the code into the edit box, mark the entire code text and then to hit Ctrl + K which indents the code properly.

\$\endgroup\$
3
\$\begingroup\$

In my opinion:

  • The maximum number of attempts should be a constant. Your code should reflect your design and specification: why would an information as important as the maximum number of attempts change in the name of a print statement?
  • The while loop would be better off as a for loop because, the way I see it, you don't want it to loop until a certain a condition is met (a certain user input, for example). You actually want it to run at most three times or break out of it before if the answer is right. The end_game variable is, in my opinion, unnecessary.
  • I think it would make the code more organized if you isolate your question in a function.

Here's the code that shows those observations:

def question_what_is_the_capital_of_peru():
    MAX_ATTEMPTS = 3

    print('What is the capital city of Peru?')

    for i in xrange(MAX_ATTEMPTS, 0, -1):
        if i > 1:
            answer = raw_input('Enter your answer. You have {} attempts left: '.format(i))
        else:
            answer = raw_input('Enter your answer. You have {} attempt left: '.format(i))
        answer = answer.capitalize()
        if answer == 'Lima':
            print('You got it right')
            return
        print('Wrong! Try again')

    print('You have no more attempts remaining')
    print('The correct answer is Lima')


if __name__ == '__main__':
    question_what_is_the_capital_of_peru()
\$\endgroup\$
  • \$\begingroup\$ If you're going to wrap it in a function, why not pass arguments like question and answer to add more advantage to having a function? \$\endgroup\$ – SuperBiasedMan Oct 12 '15 at 8:52
  • \$\begingroup\$ @SuperBiasedMan Sure, it's just that the OP wanted only to ask what's the capital of Peru, 3 times. If he wants a more general Quiz function, then holroy's answer above puts him in the right direction. \$\endgroup\$ – Marcus Vinícius Monteiro Oct 12 '15 at 10:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.