Python - 遍历嵌套字典根据值填充列表时遇到'是'对象没有属性'items

0 投票
2 回答
54 浏览
提问于 2025-04-13 20:39

我正在写一段代码,目的是让用户可以从一个列表中选择多个物品。每个用户都有一个固定的空间,而每个物品都有一个特定的大小。我想根据物品的稀有程度来填充这个列表,并且只显示那些大小在用户剩余空间以内的物品。

但是,一旦用户选择了一个物品,列表更新后只显示那些在他们剩余大小范围内的物品,显示列表的代码就不再工作了,并且出现了以下错误:

AttributeError: 'str' object has no attribute 'items'

user_stage1_objects = []
selected_objects_size = 0

timeframe1 = {
    "Option1": {
        "Common": [{"Item Name": "A1", "Size": 3}, {"Item Name": "A2", "Size": 4}],
        "Uncommon": [{"Item Name": "B1", "Size": 2}, {"Item Name": "B2", "Size": 1}]
    },
    "Option2": {
        "Common": [{"Item Name": "C1", "Size": 3}, {"Item Name": "C2", "Size": 1}],
        "Uncommon": [{"Item Name": "D1", "Size": 2}, {"Item Name": "D2", "Size": 4}]
    }
}

timeframe2 = {
    "Option1": {
        "Common": [{"Item Name": "A1", "Size": 3}, {"Item Name": "A3", "Size": 2}],
        "Uncommon": [{"Item Name": "B1", "Size": 2}, {"Item Name": "B2", "Size": 1}]
    },
    "Option2": {
        "Common": [{"Item Name": "C2", "Size": 1}, {"Item Name": "C3", "Size": 3}],
        "Uncommon": [{"Item Name": "D1", "Size": 2}, {"Item Name": "D2", "Size": 4}]
    }
}


def stage1_selection():
    global max_amount_limit, selected_objects_size, available_objects_list, user_stage1_objects

    objects_chosen = None

    user_stage1_objects = []
    available_objects_list = []

    timeframe_choice = input("""
        Select Timeframe1 or Timeframe2
        1 - Timeframe1
        2 - Timeframe2
        > """)
    if timeframe_choice == "1":
        chosen_timeframe = timeframe1
    elif timeframe_choice == "2":
        chosen_timeframe = timeframe2
    else:
        print("Not a valid choice, try again")

    while objects_chosen is None:
        if (max_amount_limit - selected_objects_size) > 3:
            if chosen_timeframe == timeframe1:
                available_objects_list = timeframe1["Option1"]["Common"]
            elif chosen_timeframe == timeframe2:
                available_objects_list = timeframe2["Option2"]["Common"]
        elif (max_amount_limit - selected_objects_size) < 4:
            available_objects_list = []
            if chosen_timeframe == timeframe1:
                available_objects_list = {
                    options: {
                        rarity: [
                            item for item in items
                                if item["Size"] < 4
                        ]
                            for rarity, items in options.items()
                                if rarity == "Common"
                    }
                        for option, options in timeframe1.items()
                            if option == "Option1"
                }
            elif chosen_timeframe == timeframe2:
                available_objects_list = {
                    options: {
                        rarity: [
                            item for item in items
                                if item["Size"] < 4
                        ]
                            for rarity, items in options.items()
                                if rarity == "Common"
                    }
                        for option, options in timeframe2.items()
                            if option == "Option1"
                }
        elif (max_amount_limit - selected_objects_size) < 3:
            available_objects_list = []
            if chosen_timeframe == timeframe1:
                available_objects_list = {
                    options: {
                        rarity: [
                            item for item in items
                                if item["Size"] < 3
                        ]
                            for rarity, items in options.items()
                                if rarity == "Common"
                    }
                        for option, options in timeframe1.items()
                            if option == "Option1"
                }
            elif chosen_timeframe == timeframe2:
                available_objects_list = {
                    options: {
                        rarity: [
                            item for item in items
                                if item["Size"] < 3
                        ]
                            for rarity, items in options.items()
                                if rarity == "Common"
                    }
                        for option, options in timeframe2.items()
                            if option == "Option1"
                }

        object_availability = available_objects_list
        object_itr = 0
        for i in object_availability:
            print(object_itr, end=' - ')
            for key, val in i.items():
                print(key, ": ", val, end='\n    ')
            print()
            object_itr = object_itr+1

        chosen_object_index = input("> ")
        chosen_object_index = int(chosen_object_index)
        user_stage1_objects.append(object_availability[chosen_object_index]["Item Name"])

        selected_objects_size = selected_objects_size + object_availability[chosen_object_index]["Size"]

        if max_amount_limit == selected_objects_size:
            objects_chosen = "Done"
        else:
            continue_object_selection = input("""
        You have """+str(int(max_amount_limit - selected_objects_size))+""" amounts left.

        Do you want to select more objects from Option1, or move on to Option2?
        1 - Continue with Option1
        2 - Move on to Option2

        >""")

            if continue_object_selection == "1":
                objects_chosen is None
            elif continue_object_selection == "2":
                objects_chosen - "Done"
            else:
                print("Not a valid choice, try again")

def fill_chosen_objects():
    global max_amount_limit, selected_objects_size, available_objects_list, user_stage1_objects

    max_amount_limit = 5

    selecting_objects = input("""
        Would you like to see available choices from Option1?

        1 - Yes
        2 - No

    > """)
    
    if selecting_objects == "1":
        stage1_selection()
    elif selecting_objects == "2":
        objects_chosen = "Done"

    return user_stage1_objects

fill_chosen_objects()

抱歉这里代码有点长,但我之前尝试过发一些小段代码,结果在大代码中应用时又不行。

基本上,一旦用户考虑了最大限制(max_amount_limit)和他们已经选择的物品总大小,他们就不应该看到任何大于他们剩余空间的物品。

我第一次能看到物品列表,但当我尝试查看列表选择第二个物品时就崩溃了。

在这一行出现了AttributeError: 'str' object has no attribute 'items'的错误:

for key, val in i.items():

谢谢

2 个回答

1

你多次把你的 available_objects_list 变量赋值为一个字典里的值。

当你用 for i in object_availability: 来遍历字典时,i 会被设置为字典的键,而在你的情况中,这些键是字符串。

比如,你可以把:

available_objects_list = {
    options: {
        rarity: [
            item for item in items
                if item["Size"] < 4
        ]
            for rarity, items in options.items()
                if rarity == "Common"
    }
        for option, options in timeframe1.items()
            if option == "Option1"
}

换成

available_objects_list = [
    {
        options: {
            rarity: [
                item for item in items
                    if item["Size"] < 4
            ]
                for rarity, items in options.items()
                    if rarity == "Common"
        }
            for option, options in timeframe1.items()
                if option == "Option1"
    }
]
1

看看这个简化的例子,它可以计算剩余的空间,并给用户提供一个可以放进去的物品列表。我觉得这可能会帮助你解决问题。

def get_timeframe():
    timeframe1 = {
        "Option1": {
            "Common": [
                {"Item Name": "A1", "Size": 3},
                {"Item Name": "A2", "Size": 4}
            ],
            "Uncommon": [
                {"Item Name": "B1", "Size": 2},
                {"Item Name": "B2", "Size": 1}
            ]
        },
        "Option2": {
            "Common": [
                {"Item Name": "C1", "Size": 3},
                {"Item Name": "C2", "Size": 1}
            ],
            "Uncommon": [
                {"Item Name": "D1", "Size": 2},
                {"Item Name": "D2", "Size": 4}
            ]
        }
    }

    timeframe2 = {
        "Option1": {
            "Common": [
                {"Item Name": "A1", "Size": 3},
                {"Item Name": "A3", "Size": 2}
            ],
            "Uncommon": [
                {"Item Name": "B1", "Size": 2},
                {"Item Name": "B2", "Size": 1}
            ]
        },
        "Option2": {
            "Common": [
                {"Item Name": "C2", "Size": 1},
                {"Item Name": "C3", "Size": 3}
            ],
            "Uncommon": [
                {"Item Name": "D1", "Size": 2},
                {"Item Name": "D2", "Size": 4}
            ]
        }
    }

    while True:
        timeframe_choice = input("""
            Select Timeframe1 or Timeframe2
            1 - Timeframe1
            2 - Timeframe2
            > """)

        if timeframe_choice == "1":
            return timeframe1

        if timeframe_choice == "2":
            return timeframe2

        print("Not a valid choice, try again")

def select_item(available_objects_list):
    while True:
        for index, item in enumerate(available_objects_list):
            print(index, item)
        chosen_object_index = int(input("Pick One: "))
        try:
            return available_objects_list[chosen_object_index]
        except IndexError:
            pass

def stage1_selection(max_amount_limit, chosen_timeframe):
    user_stage1_objects = []
    available_objects_list = []
    option_choice = "Option1"

    while (remaining_space := max_amount_limit - sum(item["Size"] for item in user_stage1_objects)) > 0:
        print(f"You have {remaining_space} space left in your pack.")
        available_objects_list = [
            {**item, **{"rarity": rarity}}
            for rarity, items in chosen_timeframe[option_choice].items()
            for item in items
            if item["Size"] <= remaining_space
        ]
        user_stage1_objects.append(select_item(available_objects_list))

    return user_stage1_objects

max_amount_limit = 5
chosen_timeframe = get_timeframe()
user_stage1_objects = stage1_selection(max_amount_limit, chosen_timeframe)

print("You have selected: ")
for item in user_stage1_objects:
    print(f"\t{item}")

撰写回答