Code critique (vending machine)

This is simplistic, but just wanted to get thoughts about how this was written. I plan on expanding upon it latter.

def vending_machine(money):
  '''Return a candy of a customer's choice'''

  options = {'A1' : {0.75 : "Snickers"}, 'B2' : {1.00 : "Butterfinger"}}

  vending_codes = options.keys() #Codes for each vending machine item

  customer_choice = input("Enter a selection: ") #Represents the customers desired vending machine option

  candy = options.get(customer_choice) #Retrieve candy and cost information from the code entered

  if customer_choice in vending_codes:
    return "Enjoy your " + candy[money]
  else:
    return "Try another option."




print(vending_machine(0.75))

7 comments · 100% upvoted · other discussions

comments

Grorco

This seems like a decent start to me, you could just use tuples for the (name, price) of the candy if it is going to be static or a list. then you could just candy[0] or candy[1]. If you want to keep it a dictionary I would suggest doing something like {'money': 0.75, 'name': "Snickers"}, for better clarity later on in the code. Also you can concatenate strings like that, but if it starts getting more complicated string formating works much better. So "Enjoy your {}".format(candy[name])

Ben_HH [OP]

I'm thinking dictionaries might be better. I intend on having the machine reflect the total quantity of each candy after a selection. If the customer wants to make a subsequent purchase the quantities will be up to date.

If I remember correctly, tuples might not work due to their immutability if I implement the aforementioned.

Grorco

So then you could do something like {'name': "Snickers", 'price': 0.75, 'quantity': 20}

Vaphell

no problem with dictionaries but tuples as a representation of product type would work too. If immutability is a problem, a list is pretty much the same thing but mutable. Unpacking is a nice, convenient feature of both.

stuff = {'A1': ('Coke 0.33', 0.50, 25) }

product, price, in_stock = stuff['A1']
# decrement in_stock
stuff['A1'] = product, price, in_stock - 1   # replaces previous tuple with one with new in_stock
fiskenslakt

This is good, but here are some things I would change:

1) Line 6 is redundant, you can remove it and change line 12 to be as follows:

if options.get(customer_choice) is not None:

Note that I do is not None instead of != None, this is on purpose and convention for comparing against None.

2) I would structure your dictionary differently, something like this:

options = {'A1': {'item': 'Snickers', 'price': 0.75}, 'B1': {'item': 'Butterfinger', 'price': 1}}

This is a lot clearer since it's weird to associate the item with the price, many items can have the same price. You don't have to worry about conflicts the way you're doing it or anything, but readability and clarity for the programmer is just as important as functionality.

3) Lastly a good addition as I'm sure you were planning to implement in the future, would be to check that the price is not more than the amount "placed into the machine". With the way I structured the data, this new feature would be a lot clearer, as you can do something like:

if candy[price] > money:
    return 'Insufficient funds'

instead of:

if candy > money:
    return 'you get the point'

Let me know if you have any questions.

fiskenslakt

Also I would rename some variables, for example I would change money to credit, and candy to selection.

That way your code could be like:

if selection[price] > credit:

And instead of:

return "Enjoy your " + candy[money]

you could have:

return "Enjoy your " + selection[item]

even better:

return "Enjoy your {}".format(selection[item])

Ben_HH [OP]

Here is a more complete version. Anything else that could use improvement?

def vending_machine(money):
      '''Return a candy of a customer's choice'''

      options = {'A1' : {'candy' : "Snickers", 'price' : 0.70, 'quantity' : 3}, 'B1' : {'candy' : "Butterfinger", 'price' : 0.85, 'quantity' : 2}, 'C1' : {'candy' : "Twix", 'price' : 0.65, 'quantity' : 3}, 'D1' : {'candy' : "M&Ms", 'price' : 0.95, 'quantity' : 6}}

      while True:
        try:
         vending_code = input("Enter a selection: ").upper() #Represents the customers desired vending machine option
         selection = options[vending_code]

        except KeyError:
          print("Invalid Selection...")

        else:
          if not selection['quantity']:
            print(f"There are no more {selection['candy']} candy bars. Please make another selection. ")

          elif selection['quantity'] and money < selection['price']:
            balance = round(abs(selection['price'] - money), 2)

            while balance > 0:
              additional_payment = float(input(f"You need ${balance} more."))
              balance -= additional_payment

            selection['quantity'] -= 1
            print(f"Enjoy your {selection['candy']} and your change is ${balance}")

            return selection['candy']
          else:
            change = round(money - selection['price'], 3)

            print(f"Enjoy your {selection['candy']} and your change is ${change}")

            selection['quantity'] -= 1

            return selection['candy']

      print(vending_machine(.90))