AttributeError: у объекта «NoneType» нет атрибута «get» - текстовая интерактивная история на python - PullRequest
0 голосов
/ 05 ноября 2018

Я пытаюсь создать текстовый интерактивный рассказ на python, но получаю эту ошибку: AttributeError: у объекта 'NoneType' нет атрибута 'get'

Мой код довольно длинный, поэтому я опубликую часть истории, которая получает эту ошибку:

approach = {'sceneText': "Following the map from the old man in the tavern, you arrive at a large hill,"
                        "covered with ancient standing stone forming the shape of a skull if viewed from a high vantage "
                        "point.", \

    'choices': ["Enter the Tomb of Horrors!", "Run Away! (Wuss)"], 'nextScene':["Entrance", "Runaway"]}
def main():
    story = {"Approach":approach, "Runaway":runaway, "Entrance":entrance, "Sealed":sealed, "Collapse":collapse, "Hallway":hallway, "Demon":demon, "PurpleHaze":purplehaze, "Damn":damn, "PitTrap":pittrap, "Gargoyle":gargoyle, "MoreSpikes":morespikes}
    sceneData = story['Approach']

    while(True):
        #.get metehod returns value for the given key
        print(sceneData.get('sceneText'))
        print("Choices: ")
        for choice in sceneData.get('choices'):
            print(choice)
        user_choice = input("Select a choice: ")
        sceneData = story.get(user_choice)

if __name__ == '__main__':
    main()

При запуске:

Following the map from the old man in the tavern, you arrive at a large hill,covered with ancient standing stone forming the shape of a skull if viewed from a high vantage point.
Choices: 
Enter the Tomb of Horrors!
Run Away! (Wuss)
Select a choice: Enter the Tomb of Horrors!
Traceback (most recent call last):
  File "story.py", line 75, in <module>
    main()
  File "story.py", line 67, in main
    print(sceneData.get('sceneText'))
AttributeError: 'NoneType' object has no attribute 'get'

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Проблема здесь в том, что вы ничего не назначаете, потому что там нет ключа, соответствующего одному из предложенных вариантов, эффективно устанавливая sceneData в None

Затем на следующей итерации цикла выдается ошибка print(sceneData.get('choices'), так как теперь sceneData None и больше не dict.

story.get(user_choice)

Это относится к story dict:

story = {
    "Approach":approach, "Runaway":runaway, 
    "Entrance":entrance, "Sealed":sealed, 
    "Collapse":collapse, "Hallway":hallway, 
    "Demon":demon, "PurpleHaze":purplehaze, 
    "Damn":damn, "PitTrap":pittrap, 
    "Gargoyle":gargoyle, "MoreSpikes":morespikes
}

Как видите, в story нет ключа, который соответствовал бы любому из ваших choices значений списка.

Возможно, вы захотите сопоставить выбранный номер следующей сцене;

Например

choices: {
    1: { 'choice-text': 'Enter the Tomb of Horrors!, 'nextScene': 'someScene' }
}

Затем пользователь должен ввести номер выбора и написать код, который установит следующую сцену на основе клавиши nextScene.

0 голосов
/ 05 ноября 2018

Как уже упоминалось в других ответах, вы ссылаетесь на несуществующий ключ в story, поэтому он выдает ошибку. Короче говоря, вот как работает ваш код:

# Iteration 1 
print(sceneData.get('sceneText'))
# evals to approach.get('sceneText'))
# prints flavour text

print("Choices: ")
for choice in sceneData.get('choices'):
    # evals to approach.get('choices')
    print(choice)
    # print list of choices within approach dict

user_choice = input("Select a choice: ")

# user inputs "Enter the Tomb..."
sceneData = story.get(user_choice)
# evals to sceneData = story.get("Enter the Tomb...")
# Since story does not have an "Enter the Tomb" key, it returns None by default.
# sceneData = None

# ---

# Iteration 2
print(sceneData.get('sceneText'))
# evals to None.get('sceneText'))
# errors out

В вашей структуре кода есть две ключевые проблемы:

  1. Вы не проверяете ввод. Т.е., если пользователь ввел «Выход», он все равно потерпит крах. У вас должна быть хотя бы базовая проверка:

    while True:
        user_choice = input("Select a choice: ")
        if user_choice in sceneData.get('choices'): break
        print('That was an invalid choice, try again.')
    
  2. На самом деле вы ничего не делаете с введенным выбором. Нет ничего, что содержало бы ключ "Enter the Tomb..." в вашем коде, и оно ограничено ошибкой с помощью метода .get("Enter the Tomb...").

Вы можете сослаться на index вариантов в вашем approach дикте и получить nextScene (что немного больше работы):

scene_index = sceneData.get('choices').index(user_choice)
sceneData = story.get('nextScene')[scene_index]

Или вы можете реструктурировать свой код так, чтобы choices были dicts примерно так:

approach = {...    
    'choices': {
        "Enter the Tomb of Horrors!": "Entrance", 
        "Run Away! (Wuss)": "Runaway"
    }
}

А когда вам нужно choices, позвоните по этому номеру:

sceneData.get('choices').keys()

Если вам нужен nextScene, позвоните по номеру:

sceneData = story.get(sceneData.get('choices').get(user_choice))

Есть много способов справиться с этим. Это зависит от ваших предпочтений.

0 голосов
/ 05 ноября 2018

Когда вы переназначаете screenData на основе пользовательского ввода (sceneData = story.get(user_choice)), вы не гарантируете, что вы ввели что-то действительное. Если они вставят что-то, для чего у вас нет screenData, вы вернете None из вызова .get(), а затем при попытке доступа к screenData[screenText] вы получите ошибку NoneType.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...