You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python OOP咖啡机代码调用get_items报缺少self参数错误求助

OOP咖啡机程序self参数缺失报错排查

问题场景

  • 学习Udemy平台Python课程时,编写基于面向对象(类与对象)实现的咖啡机程序
  • 课程演示代码可正常运行,本地运行抛出如下报错:
Traceback (most recent call last):
  File "c:\Users\Armand S\Desktop\Python Files\D16 Coffee Machine in OOP.py", line 123, in <module>
    options = menu.get_items()
TypeError: get_items() missing 1 required positional argument: 'self'
  • 报错位置在while循环内调用menu.get_items()处,不理解实例方法为何提示需要传入self位置参数,需要排查修复方案,同时收集代码优化建议

原始问题代码

#Coffee Machine in OOP code
#Define the Moneymachine class first to process the money and currency received
class MoneyMachine: 
     CURRENCY = "$"
     #write the coin values in a dictionary
     COIN_VALUES = {
              "quarters" : 0.25,
              "dimes"    : 0.1,
              "nickles"  : 0.05,
              "pennies"  : 0.01
     }
     #we write functions using init function to initialize 
     def __init__(self):
        self.profit = 0
        self.money_received = 0
    
     def report(self):
        #Prints the report of the current profit
        print(f"Money: {self.CURRENCY}{self.profit}")

     def process_coins(self):
        #Returns the value of the total calculated coins inserted 
        print("Please insert coins.")
        for coin in self.COIN_VALUES:
            self.money_received += int(input(f"How many {coins}? ")) * self.COIN_VALUES[coin]
        return self.money_received
#define the payment function
     def make_payment(self,cost):
        self.process_coins()
        if self.money_received >= cost:
            change = round(self.money_received - cost, 2)
            print(f"Here is your {self.CURRENCY}{change} in change.")
            self.profit += cost
            self.money_received = 0
            return True
            #if payment is not enough, return False
        else:
            print("Sorry that's not enough money. Money refunded.")
            self.money_received = 0
            return False



#Next we define the Menu class and Menu items. We can model it using classes
class menuItem:
    #put in all the ingredient variables and the cost ofcourse
    def __init__(self, name, water, milk, coffee, cost):
        self.name = name
        self.cost = cost
        self.ingredients = {
               "water" : water,
               "milk"  : milk,
               "coffee": coffee
        }
#full menu with costs for different coffees
class menu:
    """Models the Menu with drinks."""
    def __init__(self):
        self.menu = [
            MenuItem(name="latte", water=200, milk=150, coffee=24, cost=2.5),
            MenuItem(name="espresso", water=50, milk=0, coffee=18, cost=1.5),
            MenuItem(name="cappuccino", water=250, milk=50, coffee=24, cost=3),
        ]        

    def get_items(self):
        #Returns all the names of the available menu items
        options = ""
        for item in self.menu:
            options += f"{item.name}/"
        return options

    def find_drink(self, order_name):
        #Searches the menu for a particular drink by name. Returns that item if it exists, otherwise returns None
        for item in self.menu:
            if item.name == order_name:
                return items
        print("Sorry that item is not available")



#After this we make the CoffeeMaker class to process the coffee
class CoffeeMaker:
    #models the coffee Machine
    def __init__(self):
        self.resources = {
           "water" : 300,
           "milk"  : 200,
           "coffee": 100,
        }

    def report(self):
        #prints out the report of the resources:
        print(f"Water: {self.resources['water']}ml")
        print(f"Milk: {self.resources['milk']}ml")
        print(f"Coffee: {self.resources['coffee']}g")

    def is_resource_sufficient(self,drink):
        #Returns True when order can be made, False if ingredients are insufficient
        can_make = True
        for item in drink.ingredients:
            if drink.ingredients[item] > self.resources[item]:
                print(f"Sorry there is not enough {item}.")
                can_make = False
        return can_make

    def make_coffee(self,order):
        #Deducts the required ingredients from the resources
        for item in order.ingredients:
            self.resouces[item] -= order.ingredients[item]
        print(f"Here's your {order.name}. Enjoy!")


#----------------------------------------------------------------------Python Part-----------------------------------------------------------------------#

money_machine = MoneyMachine()
coffee_maker = CoffeeMaker()
is_on = True
coffee_maker.report()
money_machine.report()


while is_on:
    options = menu.get_items()
    choice = input(f"What would you like? ({options}): ")
    if choice == "off":
        is_on = False
    elif choice == "report":
        coffee_maker.report()
        money_machine.report()
    else:
        drink = menu.find_drink(choice)
        
        if coffee_maker.is_resource_sufficient(drink) and money_machine.make_payment(drink.cost):
          coffee_maker.make_coffee(drink)

报错根因

Python类中定义的普通实例方法,第一个参数self会在通过类实例调用方法时,由Python自动传入,值为实例对象本身。
核心问题是没有创建menu类的实例对象,直接用类名调用了实例方法get_items(),Python无法自动绑定self参数,就会抛出缺少位置参数的错误。
除此之外代码里还有4处拼写/大小写错误,修复完核心实例化问题后依然会导致运行崩溃:

  • 类名大小写不一致:定义的类是小写开头的menuItem,但menu类初始化时引用的是大写开头的MenuItem,会触发NameError
  • process_coins方法内循环变量是coin,输入提示里写成了coins(多了s),变量未定义
  • find_drink方法内匹配到饮品后返回items(多了s),实际循环变量是item,变量未定义
  • make_coffee方法内操作资源时写的是self.resouces(少了字母r),实际属性名是self.resources,属性不存在

修复方案

  1. 按Python PEP8规范修正类名大小写:将class menuItem改为class MenuItem,class menu改为class Menu,保持类名引用一致
  2. 主程序初始化阶段,和MoneyMachine、CoffeeMaker一样,先创建Menu类的实例:
menu = Menu()
  1. 修正所有拼写错误:
    • 投币输入提示的{coins}改为{coin}
    • 查找饮品方法的返回值items改为item
    • 制作咖啡方法的self.resouces改为self.resources

修复后可运行完整代码

class MoneyMachine: 
    CURRENCY = "$"
    COIN_VALUES = {
        "quarters" : 0.25,
        "dimes"    : 0.1,
        "nickles"  : 0.05,
        "pennies"  : 0.01
    }

    def __init__(self):
        self.profit = 0
        self.money_received = 0
    
    def report(self):
        print(f"Money: {self.CURRENCY}{self.profit}")

    def process_coins(self):
        print("Please insert coins.")
        for coin in self.COIN_VALUES:
            self.money_received += int(input(f"How many {coin}? ")) * self.COIN_VALUES[coin]
        return self.money_received

    def make_payment(self,cost):
        self.process_coins()
        if self.money_received >= cost:
            change = round(self.money_received - cost, 2)
            print(f"Here is your {self.CURRENCY}{change} in change.")
            self.profit += cost
            self.money_received = 0
            return True
        else:
            print("Sorry that's not enough money. Money refunded.")
            self.money_received = 0
            return False


class MenuItem:
    def __init__(self, name, water, milk, coffee, cost):
        self.name = name
        self.cost = cost
        self.ingredients = {
            "water" : water,
            "milk"  : milk,
            "coffee": coffee
        }

class Menu:
    """Models the Menu with drinks."""
    def __init__(self):
        self.menu = [
            MenuItem(name="latte", water=200, milk=150, coffee=24, cost=2.5),
            MenuItem(name="espresso", water=50, milk=0, coffee=18, cost=1.5),
            MenuItem(name="cappuccino", water=250, milk=50, coffee=24, cost=3),
        ]        

    def get_items(self):
        options = ""
        for item in self.menu:
            options += f"{item.name}/"
        return options

    def find_drink(self, order_name):
        for item in self.menu:
            if item.name == order_name:
                return item
        print("Sorry that item is not available")
        return None


class CoffeeMaker:
    def __init__(self):
        self.resources = {
           "water" : 300,
           "milk"  : 200,
           "coffee": 100,
        }

    def report(self):
        print(f"Water: {self.resources['water']}ml")
        print(f"Milk: {self.resources['milk']}ml")
        print(f"Coffee: {self.resources['coffee']}g")

    def is_resource_sufficient(self,drink):
        if not drink:
            return False
        can_make = True
        for item in drink.ingredients:
            if drink.ingredients[item] > self.resources[item]:
                print(f"Sorry there is not enough {item}.")
                can_make = False
        return can_make

    def make_coffee(self,order):
        for item in order.ingredients:
            self.resources[item] -= order.ingredients[item]
        print(f"Here's your {order.name}. Enjoy!")


if __name__ == "__main__":
    money_machine = MoneyMachine()
    coffee_maker = CoffeeMaker()
    menu = Menu()
    is_on = True
    coffee_maker.report()
    money_machine.report()

    while is_on:
        options = menu.get_items()
        choice = input(f"What would you like? ({options}): ").lower()
        if choice == "off":
            is_on = False
        elif choice == "report":
            coffee_maker.report()
            money_machine.report()
        else:
            drink = menu.find_drink(choice)
            if coffee_maker.is_resource_sufficient(drink) and money_machine.make_payment(drink.cost):
                coffee_maker.make_coffee(drink)

可选优化建议

  • 遵循PEP8命名规范:类名使用大驼峰格式,方法、变量名使用蛇形格式,缩进统一用4个空格,避免大小写、拼写错误
  • 投币逻辑增加输入校验,捕获用户输入非整数的异常,避免程序直接崩溃
  • find_drink方法匹配不到饮品时显式返回None,同时资源检查逻辑增加None判断,避免访问空对象属性报错
  • 用户输入统一做小写转换,避免用户输入大写首字母的饮品名时匹配失败
  • 资源不足时可以一次性列出所有缺少的原料,不用每次运行只提示一种原料不足

内容的提问来源于stack exchange,提问作者Armand Surbakti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:21:32