Python Noob - Ищет предложения против спагетти и избегает избыточного кода - PullRequest
0 голосов
/ 23 января 2020

Первый пост здесь. Я хотел донести это до вас, ребята, потому что я ищу некоторые глубокие отзывы и мои подходы, возвращающиеся в этот мир. Мой основной опыт работы с Javascript на фронтовой работе, и я не написал ни одного письма python до вчерашнего дня, так что извините за беспорядок.

Я пытаюсь увидеть, что вы может показаться, как некоторые из готовых предложений для сокращения или очистки этого кода. Может быть, какие-то вопиющие предметы «пожалуйста, никогда больше не делайте этого», или какое-либо понимание, которое у вас могло бы быть.

Это консольная игра в угадывание чисел, в настоящее время 1 - 10. Она работает с некоторыми ошибками. Одна из основных причин, которые меня сбивают с толку (и я уверен, что это просто) - если вы угадываете правильный ответ с последней попытки (в данном случае 3-й), он не запускает код «Поздравляю». Он запускает раздел «Вы потерпели неудачу».

Просто ищите какие-либо предложения или предложения любого рода, чтобы помочь оценить МОЕ мышление и подход к решению проблем на этом языке. Кроме того, если в Интернете есть лучшее место для такого рода занудства, дайте мне знать. Спасибо!

from random import randint


def guessing_game():
    # Set the count and limits for the loop and game length.
    guess_count = 0
    guess_limit = 2
    # Ask the user to take a guess.
    guess = int(input("I'm thinking of a number between 1 and 10... "))
    # Randomize the answer. Change the range according to preference.
    the_answer = randint(1, 10)
    # Start the loop
    while guess_count < guess_limit:

        if guess == the_answer:  # The user wins and is prompted to play again. Init function would probably be useful.
            print(f"Congrats, you won! The answer is {the_answer}!")
            restart = input("Play again? ")
            if restart.upper() == "Y":
                guessing_game()
            else:  # The user declines to play and we break out of the loop.
                print("Okay, thanks for playing! ")
                break
            break
        elif guess != the_answer:  # The user guessed the wrong answer. Ask again and add to the count.
            print("Oops, try again.")
            guess = int(input("I'm thinking of a number between 1 and 10... "))
            guess_count += 1

        if guess_count == guess_limit:  # Shucks, the user failed. Inform them of their failure and offer redemption.
            print('Sorry, you failed.')
            restart = input("Play again? ")
            if restart.upper() == "Y":
                guess_count = 0
                guessing_game()
            else:  # The user opted out of continuing this exciting adventure.
                print("Okay, thanks for playing! ")
                break


guessing_game()

1/23/2020 - 12:45 EST. Обратите внимание на обновленный код ниже для @ An0n1m1ty. С этим обновленным кодом я могу сделать до 4 неправильных догадок, прежде чем он закончится. Во втором неверном предположении не выводится сообщение «Упс», а в четвертом неправильном предположении программа просто заканчивается. Нет сообщения «Вы проиграли» или подсказка для повторного воспроизведения.

Однако выигрыш, похоже, работает правильно. Я go над ним и попытаюсь определить логи c за текущим поведением. Вы можете увидеть изменения, которые я сделал с комментариями, начинающимися с 'CHANGE'.

Кроме того, если есть лучшее место для отображения этих обновлений кода, пожалуйста, дайте мне знать. Я не поместил это в ответ, потому что это не ответ. Извините, я новичок.

from random import randint


def guessing_game():
    # Set the count and limits for the loop and game length.
    guess_count = 0
    guess_limit = 2
    # CHANGE Moved guess input from here to beginning of loop
    # Randomize the answer. Change the range according to preference.
    the_answer = randint(1, 10)
    # Start the loop
    while guess_count < guess_limit:
        # CHANGE Ask the user to take a guess.
        guess = int(input("I'm thinking of a number between 1 and 10... "))
        if guess == the_answer:  # The user wins and is prompted to play again. Init function would probably be useful.
            print(f"Congrats, you won! The answer is {the_answer}!")
            restart = input("Play again? ")
            if restart.upper() == "Y":
                guessing_game()
            else:  # The user declines to play and we break out of the loop.
                print("Okay, thanks for playing! ")
                break
            break
        elif guess != the_answer and guess_count != guess_limit:  # CHANGE The user guessed the wrong answer.
            print("Oops, try again.")
            guess = int(input("I'm thinking of a number between 1 and 10... "))
            guess_count += 1

        elif guess_count == guess_limit:  # CHANGE Shucks, the user failed. Inform them of their failure and offer redemption.
            print('Sorry, you failed.')
            restart = input("Play again? ")
            if restart.upper() == "Y":
                guess_count = 0
                guessing_game()
            else:  # The user opted out of continuing this exciting adventure.
                print("Okay, thanks for playing! ")
                break


guessing_game()

1/23/2020 - 7:45 вечера EST Итак, с этими изменениями мы намного ближе. Основная проблема заключается в том, что если вы получите три неправильных ответа, программа просто завершится. Нет сообщения об ошибке или подсказки для воспроизведения снова. Я полагаю, что это потому, что условие l oop выполняется после трех попыток, поэтому секция l oop и секция

elif guess_count == guess_limit:

никогда не имеют шансов на выполнение. Я решил эту проблему, изменив

while guess_count < guess_limit:

на

while guess_count <= guess_limit: 

, что позволяет запустить вышеупомянутый раздел и снова начать воспроизведение. Единственное, что с этим решением, это то, что l oop работает еще один раз за пределами догадки_имита из-за <= в начале l oop. Таким образом, вам нужно уменьшить на 1, что вы хотите на самом деле. проиграв или выиграв в следующем раунде и выбрав НЕ продолжать, он скажет: «Хорошо, спасибо за игру», и игра сразу начинается, а не заканчивается. Вот где я сейчас нахожусь. </p>

Большое спасибо за вашу помощь! Звучит странно, я уверен, но это заставляет меня снова смотреть на нее sh.

Ответы [ 2 ]

0 голосов
/ 24 января 2020

Ручная while петли - почти всегда неправильный ответ в Python. Гораздо проще сделать for l oop вместо range, которое выполняется до указанного количества раз. Кроме того, циклы Python for могут принимать блок else, который выполняется, когда l oop завершается, но не выполняется, если вы break (или return) или исключение), что делает их идеальными для сценария «иголка в стоге сена» ios, где игла не найдена (петли while также могут иметь блоки else, но петли for являются лучший вариант здесь). Он также позволяет перемещать общий код (код, который выполняется независимо от того, угадал ли он правильно или нет, в данном случае проверка «новая игра») за пределы for и else, поэтому вы либо выводите один набор данных в пределах l oop и break для общего кода, или l oop выполняется до завершения, и блок else выводит другое сообщение перед общим кодом.

Таким образом, вы могли бы быть значительно упрощены используя for / else для:

from random import randint

def guessing_game():
    # Set the count and limits for the loop and game length.
    guess_limit = 2  # Allows up to two guesses
    # Randomize the answer. Change the range according to preference.
    the_answer = randint(1, 10)
    for guess_count in range(guess_limit):
        guess = int(input("I'm thinking of a number between 1 and 10... "))
        if guess == the_answer:
            print(f"Congrats, you won! The answer is {the_answer}!")
            break  # Go to common code for retry
        elif guess_count != guess_limit:  # Don't need to retest guess != the_answer; this is an else that never executes unless they weren't equal 
            print("Oops, try again.")
            # Don't need to prompt for input again, we'll prompt at top of loop
    else:
        # Only prints if loop ran to completion without breaking
        print('Sorry, you failed.')

    # Common code run for both success and failure:
    restart = input("Play again? ")
    if restart.upper() == "Y":
        guessing_game()
    else:
        print("Okay, thanks for playing! ")

if __name__ == '__main__':  # Get in the habit of using the import guard now; it's not necessary yet, but when it is, you want to be in the habit
    guessing_game()

Обратите внимание, что неограниченная рекурсия здесь потенциально проблематична c. Если пользователь играет около тысячи раз, вы достигнете предела Python рекурсии. Если это проблема, я бы изменил рефакторинг, чтобы отделить «одну игру» от «всех игр», и чтобы «все игры» были реализованы как al oop, поэтому вам не нужно повторяться, чтобы играть в другую игру:

from random import randint

def play_one_game():
    # Set the count and limits for the loop and game length.
    guess_limit = 2  # Allows up to two guesses
    # Randomize the answer. Change the range according to preference.
    the_answer = randint(1, 10)
    for guess_count in range(guess_limit):
        guess = int(input("I'm thinking of a number between 1 and 10... "))
        if guess == the_answer:
            print(f"Congrats, you won! The answer is {the_answer}!")
            break  # Go to common code for retry
        elif guess_count != guess_limit:  # Don't need to retest guess != the_answer; this is an else that never executes unless they weren't equal 
            print("Oops, try again.")
            # Don't need to prompt for input again, we'll prompt at top of loop
    else:
        # Only prints if loop ran to completion without breaking
        print('Sorry, you failed.')

def guessing_game():
    keep_playing = True
    while keep_playing:
        play_one_game()
        # Common code run for both success and failure:
        keep_playing = input("Play again? ").upper() == "Y"
    print("Okay, thanks for playing! ")

if __name__ == '__main__':  # Get in the habit of using the import guard now; it's not necessary yet, but when it is, you want to be in the habit
    guessing_game()

Этот подход также помогает минимизировать сложность; guessing_game используется для выполнения двух едва связанных вещей:

  1. Воспроизвести один экземпляр игры
  2. Определить, стоит ли играть в другую игру

Разделяя их, вы разделяете два поведения, поэтому понимание каждой функции проще в отдельности.

Последнее предложение: не существует замечательного способа справиться с сообщением «не выдавать Oops на последнем l oop». «Случай, который я могу придумать не по себе, но есть« не страшные »способы устранить необходимость в тесте, который не пройдёт в большинстве циклов. Самый простой подход состоит в том, чтобы отобразить дополнительное сообщение как часть ввода, используя дополнительное сообщение, которое изначально пусто и впоследствии безоговорочно устанавливается в сообщение «oops», поэтому оно используется для всех последующих циклов. Для этого вы просто замените:

for guess_count in range(guess_limit):
    guess = int(input("I'm thinking of a number between 1 and 10... "))

на:

extra = ''  # No oops message the first time
for _ in range(guess_limit):  # Don't even name guess_count, we never use it; by convention, _ means unused variable
    guess = int(input(extra + "I'm thinking of a number between 1 and 10... "))
    extra = "Oops, try again.\n"  # From now on, oops incorporated into prompt

, что позволит вам полностью удалить:

    elif guess_count != guess_limit:
        print("Oops, try again.")

, заменяя на л oop условная ветвь с безусловными путями выполнения (что также облегчает тестирование кода, поскольку неиспользуемых или слабо используемых путей меньше).

0 голосов
/ 23 января 2020

В следующем коде проблема заключается в следующем:

elif guess != the_answer:  # The user guessed the wrong answer. Ask again and add to the count.
    print("Oops, try again.")
    guess = int(input("I'm thinking of a number between 1 and 10... "))
    guess_count += 1

Когда пользователь наконец получит правильный ответ, будет выполнен следующий бит кода:

if guess_count == guess_limit:  # Shucks, the user failed. Inform them of their failure and offer redemption.
    print('Sorry, you failed.')
    restart = input("Play again? ")
    if restart.upper() == "Y":
        guess_count = 0
        guessing_game()
    else:  # The user opted out of continuing this exciting adventure.
        print("Okay, thanks for playing! ")
        break

Теперь, если пользователь находится на третьем предположении, guess_count == guess_limit будет true, и код будет исполнен со словами «Извините, вы не смогли»

Чтобы устранить проблему, я сделал следующее: Переместить

guess = int(input("I'm thinking of a number between 1 and 10... "))

до первой строки l oop. то есть:

while guess_count < guess_limit:
    guess = int(input("I'm thinking of a number between 1 and 10... "))

Затем измените:

elif guess != the_answer:

на

elif guess != the_answer and guess_count != guess_limit:

Затем измените:

elif guess != the_answer and guess_count != guess_limit:  # CHANGE The user guessed the wrong answer.
    print("Oops, try again.")
    guess = int(input("I'm thinking of a number between 1 and 10... "))
    guess_count += 1

на

elif guess != the_answer and guess_count != guess_limit:  # CHANGE The user guessed the wrong answer.
    print("Oops, try again.")
    guess_count += 1

Затем измените:

guess_limit = 2

на

guess_limit = 3

Наконец, измените:

if guess_count == guess_limit:

на

elif guess_count == guess_limit:
...