0

So I am trying to define a class and create methods to add, remove, edit, and display from a list. This is what I have so far and I am running into the 'list' object not callable error. I am using some instruction from my class for a lot of the code from a similar project so I am not exactly sure on the pieces that return the added and edited orders. Here is what I have so far:

class Order:
    
    amount = 0.0
    orderType = ""
    number = 0
    
    def __init__(self, amount, orderType, number):
        self.amount = amount
        self.orderType = orderType
        self.number = number

    def setamount(self, amount):
        self.amount = amount

    def setordertype(self, orderType):
        self.orderType = orderType

    def setnumber(self, number):
        self.number = number
    
    def getamount(self):
        return self.amount

    def getordertype(self):
        return self.orderType

    def getnumber(self):
        return self.number
    
    def displayOrder(self):
        print("******************")
        print("*** Order List ***")
        print("Order Number: ", self.number)
        print("Order Type: ", self.orderType)
        print("Order Amount: ", self.amount)
        print("******************")
    
    def displayMenu():
        print("============Welcome to Pizza Palace - Class Demo============")
        print("1. Display Orders.")
        print("2. Add New Order.")
        print("3. Remove Order.")
        print("4. Edit Order.")
        print("5. Save Order.")
        print("9. Exit Program.")
        print("")
        return int(input("Selection: "))
    
    orders = []
    
    def addOrder(orders):
        number = int(input("Enter your order number: "))
        orderType = input("Enter your order type: ")
        amount = float(input("Enter your order amount: "))
        orders[number] = orders(number, orderType, amount)
        return orders
    
    def removeOrder(orders):
        removeNumber = int(input("Which order would you like to remove? "))
        if removeNumber in orders:
            del orders[removeNumber]
        else:
            print("Order not found")
        return orders

    def editOrder(orders):
        badOrder = int(input("Which order would you like to edit?"))
        if badOrder in orders:
            newNumber = int(input("Enter new order number: "))
            newType = input("Enter new order type: ")
            newAmount = float(input("Enter new order amount: "))
            orders[badOrder] = orders(newNumber, newType, newAmount)
        else:
            print("Order not found")
        return orders
    
    def printOrder(orders):
        if len(orders) == 0:
            print("No orders")
        else:
            for x in orders.keys():
                orders[x].displayData()
    
    selection = displayMenu()
    
    if selection != 9:
        if selection == 1:
            printOrder(orders)
        elif selection == 2:
            addOrder(orders)
        elif selection == 3:
            removeOrder(orders)
        elif selection == 4:
            editOrder(orders)
        elif selection == 5:
            saveOrder(orders)
        else:
            print("Invalid input")
    else:
        print("Exiting Program...")
jfaccioni
  • 7,099
  • 1
  • 9
  • 25
  • `orders[number] = orders(number, orderType, amount)` doesn't seem like a valid code. Don't use the same name for different variables. – Guy Apr 18 '22 at 13:34
  • Side-note: As a rule, functions either modify their argument in-place and have no useful return value (implicitly returning `None`) or they return a modified copy of the argument and leave the caller's value untouched. All your *verb*`Order` functions save `printOrder` violate this rule (both mutating `orders` and returning it). Given the nature of the work being done, mutating in place makes sense, but you should remove the `return orders` at the end of each function (none of your code makes use of it in any event). – ShadowRanger Apr 18 '22 at 13:45
  • Also, if you want this program to run until the user enters `9`, change `selection = displayMenu()` and `if selection != 9:` to `while (selection := displayMenu()) != 9:` (for modern Python, `:=`, aka "the walrus operator", lets you both assign to a name and test the value within a conditional, and this is one of the cases where it makes sense to use it). – ShadowRanger Apr 18 '22 at 13:48
  • Welcome to Stack Overflow. Please read [ask] and https://ericlippert.com/2014/03/05/how-to-debug-small-programs/ and https://meta.stackoverflow.com/questions/261592 and https://meta.stackoverflow.com/questions/359146. "and I am running into the 'list' object not callable error" Did you try to read the error message? Which line of code is it complaining about? Do you see something on that line that you expect to be a list? Do you see something on that line that tries to call the list? Do you understand why a list is not callable? Do you understand what it means to call something? – Karl Knechtel Apr 18 '22 at 13:51
  • so, following instructions from the assignment that line should read something like orders[number]=ordersData(number, orderType, amount) but when I ran it like that i got an error for no assignment of ordersData. Im just not sure how I would define that especially since this is my first time doing this with classes. The goal is to add the input to the list under the parameters of the class im just not sure how to do that – Tyler Bailey Apr 18 '22 at 22:42
  • ShadowRanger, that is a much better solution thank you for that. I am still beginning to understand how to use the while loop. and Karl Knechtel, I see where I am getting the error, I do see something I expect to be a list, but i dont exactly understand why a list is not callable or what it means to call something. – Tyler Bailey Apr 18 '22 at 22:45

1 Answers1

1

Your problem is in addOrder (with an equivalent mistake in editOrder):

orders[number] = orders(number, orderType, amount)

which is wrong in three separate ways:

  1. You're trying to make a new Order, but you uses orders (a list) to do it, not Order (the class). You wanted orders[number] = Order(number, orderType, amount), with a similar change to editOrder
  2. You've got the argument order wrong; Order expects amount, orderType, number, but you pass number, orderType, amount, so flip those arguments (or pass them by keyword to remove ambiguity).
  3. Even that won't work, because orders is an empty list, and unlike JavaScript (which, if you're not completely new to programming, I'm guessing is the language you're most familiar with, and has unusual Array semantics that allow what you're trying to do), you're not allowed to arbitrarily insert to list indices that don't already have values in Python. For the use case you've got, the best data structure is likely a dict, which allows autovivification of arbitrary keys, so you'd want to change orders = [] to orders = {}.

As it happens, your printOrder is already written to assume orders is a dict, so few, if any, other changes are needed. Bonus: Your membership tests in removeOrder and editOrder, which would never have passed, because the integer isn't in the list, become correct (and much more efficient relative to the equivalent code needed to find an Order in your list) for free.

You have one additional error unrelated to your current problem line, namely, that you use an if, not a while, to receive input from the user, which means you'll never do more than one single operation before the program exits.

I'd suggest replacing:

selection = displayMenu()

if selection != 9:

with:

while (selection := displayMenu()) != 9:

which means you'll run until the user enters 9, not just once at most, and uses the walrus operator to both assign and test a value in the while conditional, replacing the much more verbose idiom in older Python required to write such a loop without doubling the code that assigns to selection in two places (just above the loop and at the end of the loop where it can be accidentally skipped if you ever use continue):

while True:
    selection = displayMenu()
    if selection == 9:
        break
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • This was great, I really appreciate the help. However I am still encountering an error. I fixed everything as you said, the argument order is correct and the class is referenced where it should be. When I run what I have now I get a name error saying Order is not defined. I played with some of the indentations but I cannot figure out what to do to make this work. It doesnt make sense because Order is the class but its saying that its not defined – Tyler Bailey Apr 19 '22 at 10:55
  • @TylerBailey: That's because every line from `def displayMenu():` on down, which should be dedented outside the definition of `Order`, is indented to be a part of the `Order` class (`Order` doesn't actually exist until you've finished defining it). I'd thought that was just a typo in copying your code here, but I guess it's not. Take every single line starting from `def displayMenu():`, and remove four leading spaces from it. – ShadowRanger Apr 19 '22 at 11:00
  • You have been a great help, I just have one more problem. I got everything else working I just need to add a function to save the orders dict to a text file. I am attempting to use pickle to facilitate that and I am close but when it finishes I just get some random symbols in the text file instead of the string as intended. This is what I am trying: def saveOrder(orders): pizza = open("orders.txt", "wb") for x in orders.keys(): pickle.dump(orders[x].displayOrder(), pizza) pizza.close() – Tyler Bailey Apr 19 '22 at 13:53
  • @TylerBailey: `pickle`-ed data is "random symbols". It's not going to look like text at all. If you want to save the output of `displayOrder` one after another, the simplest approach (given you write it using `print` instead of having it return the `str` that could be sent to arbitrary places) is to use `contextlib.redirect_stdout` to send `print`s to your file. [See example here.](https://tio.run/##TYw7DsMgEER7TrGiAsmiSZdL5AgRMRt5JcIiWMefy@MYuch0o3nz8iYTp1tr9MlcBEZOgqtEeim1kEzAGZPRXAKW6mQVPYBetAVfIdO@@@Hv4goGKjjKs0rgWUwn7F3BL28u0DVACS7f18cZq7mIM31wgWqOfnucxdjWDg "Python 3 – Try It Online") – ShadowRanger Apr 19 '22 at 14:31
  • @TylerBailey: Note: I tweaked the code in that TIO link to use `with` statements (so the files and redirection are definitely cleaned up when the `with` ends), and I directly iterated the `.values()` of your `dict` (because the key wasn't used for anything but getting the value, so it's simpler/more-efficient to just use the values directly). Another reasonable solution would be to rewrite `displayOrder` so it generates and returns a `str` of the data, rather than `print`ing it, so you can `write` it to arbitrary places without the `contextlib.redirect_stdout` hack. – ShadowRanger Apr 19 '22 at 14:32