5
\$\begingroup\$

I'm really new to Python (like only a month of study) and I was testing out dictionaries, so I tried to make an 'inventory' where you can pick an item from your inventory and examine it. But I can tell that I'm not doing this in the most efficient or elegant way.

Originally I thought I could make each item its separate dictionary, kind of like this:

#define what's in your inventory using a list
inventory = ["apple", "tire"]

#create a list of items with attributes using dictionaries
apple = {
    "name":"apple",
    "type":"fruit",
    "edible":"edible",
    "color":"red",
}

tire = {
    "name":"tire",
    "type":"object",
    "edible":"not edible",
    "color":"grey"
}

#explain the program to the user
print("Choose an item to examine. Items in your inventory are:")
print(*inventory, sep = ", ")

#set the loop to true
itemsloop = True

#begin the loop
while itemsloop == True:
    #ask for user input
    x = input()

But then I got stuck at the part where it's time to take the input and match it to the name of a dictionary, because one is a string and one isn't. The following code is working, but feels... inelegant and unnecessary to type out (prefix)-name, (prefix)-type, (prefix)-edible for every entry. I feel like there must be a simpler way to accomplish this that I'm just not seeing because I don't think like a programmer yet. I don't know.

If you can explain any more efficient methods with simple terminology (again, huge newbie not just to Python but programming in general), I'd really appreciate it!

#define what's in your inventory using a list
inventory = ["apple", "tire"]

#create a list of items with attributes using a dictionary
items = {
    "apple-name":"apple",
    "apple-type":"fruit",
    "apple-edible":"edible",
    "apple-color":"red",

    "tire-name":"tire",
    "tire-type":"object",
    "tire-edible":"not edible",
    "tire-color":"grey"
}

#explain the program to the user
print("Choose an item to examine. Items in your inventory are:")
print(*inventory, sep = ", ")

#set the loop to true
itemsloop = True

#begin the loop
while itemsloop == True:
    #ask for user input
    x = input()

    if x in inventory:
        #if the input matches something you have, find the attributes of
        #the item in the inventory and print them.
        print("This is a " + items[x + "-color"] + " " + 
        items[x + "-name"] + ", a type of " + items[x + "-type"] 
        + ". It is " + items[x + "-edible"] + ".")
    elif x == "quit":
        #if the player wishes to quit, end the program.
        itemsloop == False
        break
    else:
        #if the item is not recognized, let the player know.
        print("You don't have that in your inventory.")

(The sample output would be something like, "This is a red apple, a type of fruit. It is edible.")

\$\endgroup\$
1
\$\begingroup\$

To expand on the answer given by @Aries_is_there in, you should indeed make your dictionary a nested dictionary with the item names as first keys and the item properties as keys of the sub dictionaries.

You should also be aware that x in inventory is \$\mathcal{O}(n)\$ if inventory is a list, but this is mitigated when making it a dictionary, because x in items is \$\mathcal{O}(1)\$ for dictionaries.

Your printing can also be simplified by using an f-string.

I would also add a if __name__ == "__main__" guard to allow importing functions form this script from another script.

And finally, Python has an official style-guide, PEP8, which is well worth a read. You are already mostly following it, except for the missing spaces after the : in your dictionaries.

items = {"apple": {"name": "apple",
                   "type": "fruit",
                   "edible": "edible",
                   "color": "red"},
         "tire": {"name":"tire",
                  "type":"object",
                  "edible":"not edible",
                  "color":"grey"}}

if __name__ == "__main__":
    print("Choose an item to examine. Items in your inventory are:")
    print(*items.keys(), sep = ", ")

    while True:
        x = input()

        if x in inventory:
            #if the input matches something you have, find the attributes of
            #the item in the inventory and print them.
            item = items[x]
            print(f"This is a {item['color']} {item['name']}, a type of {item['type']}. It is {item['edible']}.")
        elif x == "quit":
            #if the player wishes to quit, end the program.
            break
        else:
            #if the item is not recognized, let the player know.
            print("You don't have that in your inventory.")

You could take it one level further by making it object-oriented. In this case you would probably want an Object class for which you define the magic __str__ method, which controls what happens if you do print(x).

class Object:
    def __init__(self, name, type="object", edible=False, color=None):
        self.name = name
        self.type = type
        self.edible = edible
        self.color = color

    def __str__(self):
        s = ["This is a "]
        if self.color is not None:
            s.append(self.color + " ")
        s.extend([self.name, f", a type of {self.type}."]
        s.append(f"It is {'not ' if not self.edible else ''}edible.")
        return "".join(s)


items = {"apple": Object("apple", "fruit", edible=True, color="red"),
         "tire": Object("tire", color="grey")}


if __name__ == "__main__":
    print("Choose an item to examine. Items in your inventory are:")
    print(*items.keys(), sep = ", ")

    while True:
        x = input()

        if x in items:
            #if the input matches something you have, find the attributes of
            #the item in the inventory and print them.
            item = 
            print(items[x])
        elif x == "quit":
            #if the player wishes to quit, end the program.
            break
        else:
            #if the item is not recognized, let the player know.
            print("You don't have that in your inventory.")
\$\endgroup\$
  • \$\begingroup\$ Thank you very much for the thorough explanation. I didn't know you could nest dictionaries! I'm still new to a lot of the things included in your post, so i will be doing googling for a while, haha. Do you have any recommendations on a good newbie explanation for magic methods? I had never heard of those. \$\endgroup\$ – Red Nov 14 '18 at 18:09
3
\$\begingroup\$

As you use item's name to search the item information, so you can design the name as the key of items hash table.

items = {
    "apple":
        {
            #type, edible,color information
        },
    ...
}
\$\endgroup\$
  • \$\begingroup\$ I didn't understand that you could use dictionaries as dictionary keys. Thank you. \$\endgroup\$ – Red Nov 14 '18 at 17:57
  • \$\begingroup\$ haha as long as you get @Graipher answer, he did a good explain \$\endgroup\$ – Aries_is_there Nov 14 '18 at 18:22
  • 1
    \$\begingroup\$ @Red You actually can't. But you can use them as dictionary values. If you want to use them as keys you would have to convert the dictionary into a tuple of key, value tuples first, so it is hashable. This would be sensitive to the order then, though. \$\endgroup\$ – Graipher Nov 14 '18 at 19:17

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.