首页 > 解决方案 > Using __init__ in OOP

问题描述

I am learning to develop code using OOP. However I am having issues understanding when to use the __init__ constructor. Is __init__ mandatory in OOP? If so how would I use __init__ ?

What the following code does is takes the users requested pizza size and toppings and returns and final total.

When I run the following code:

class Pizza:
    """ customer orders pizza size and pizza toppings"""

    def size_menu(self): # Provides user a menu
        
        self.menu_s = """
        What size pizza would you like?
            _____________________________________________________________
            | 1: Small  |  2: Large  |  3: Extra Large  |  4: Party Size |
            |  $6.23    |   $10.23   |      $12.23      |      $24.23    |
            |___________|____________|__________________|________________|
            """
        print(self.menu_s)
        return self.menu_s

    def size_order(self): # Gets size wanted and returns pizza total. 
        size_mappings = {
            1: "Small",
            2: "Large",
            3: "Extra Large",
            4: "Party Size"
            }

        cost_mappings = {
            "Small": 6.23,
            "Large": 10.23,
            "Extra Large": 12.23,
            "Party Size": 24.23
            }

        response = input('-') # user inters 1-4 for pizza size wanted and returns a size total.
        self.size_wanted = float(response) # Turns response as a float
        self.size_wanted = size_mappings[self.size_wanted] # Size requested
        self.size_cost = cost_mappings[self.size_wanted] # Cost of size

        print(f"Getting your {self.size_wanted} pizza ready.")
        print(f"Your current total is: ${self.size_cost}")
        return self.size_cost

    def topping_menu(self): # Provides user with toppings menu
        self.menu_t = """
        What toppings do you want on your pizza?
        _____________________________________________________
       |   1:Bacon      |  4:Anchovies     |  7:Black Olives |
       |   2:Pepperoni  |  5:Spinach       |  8:Chicken      |
       |   3:Mushrooms  |  6:Onions        |  9:Ground Beef  |
       |________________|__________________|_________________| 
       What toppings do you want on your pizza?
       """
        print(self.menu_t)
        return self.menu_t
       

    def topping_order(self): # Gets toppings the user wants and returns a total of all toppings. 
        topping_mappings = {
            1: 'Bacon', 
            2: 'Pepperoni', 
            3: 'Mushrooms', 
            4: 'Anchovies', 
            5: 'Spinach', 
            6: 'Onions', 
            7: 'Black Olives',
            8: 'Chicken', 
            9: 'Ground Beef'
            }

        self.requested_toppings = []

        while True:
            response = input('-')

            if response == 'q':
                break

            toppings_wanted = response
            toppings_wanted = topping_mappings[int(toppings_wanted)]
            self.requested_toppings.append(toppings_wanted)

            if toppings_wanted in topping_mappings.values():
                print(f"Adding: {toppings_wanted}")

            else:
                print(f"We do not have {toppings_wanted}")

        self.topping_total = len(self.requested_toppings) * float(1.23)

        print("\nWe are adding the requested toppings to your pizza.")
        print(f"your topping total will be: ${self.topping_total}")
        return self.topping_total

   
    def final_total(self):
        total = self.size_cost + self.topping_total
        total = float(total)
        print(f"\nYour final order total will be ${total}")



if __name__ == '__main__':
    
    customer_order = Pizza()
    customer_order.size_menu()
    customer_order.size_order()
    customer_order.topping_menu()
    customer_order.topping_order()
    customer_order.final_total()
    
    

I am wondering why would I use the __init__ constructor if the program is returning the information I am seeking? Thank you for the assistance.

标签: pythonclassoop

解决方案


虽然此代码有效,但它的可扩展性和可重用性都不是很高。

如果明天您希望允许使用来自 json 文件的输入而不是用户输入来订购比萨饼怎么办?

如果您忘记调用其中一种order方法怎么办?调用final_total会使您的程序崩溃,因为某些属性会丢失。

此外,在方法之外创建属性被认为是一种反模式,__init__因为它使代码不可读、难以理解和难以使用(目前,并非所有Pizza实例都始终具有相同的属性)。

如何让它变得更好

  1. 将所有硬编码的永久值移动为类属性。这些将在 的所有实例之间共享Pizza

  2. 获取成为inPizza所需的所有参数。这些对于每个.Pizza__init__Pizza

  3. 实现可能的排序方法Pizza。其中之一可能是from_user_input

请注意,此代码可能使用比您目前可能知道的更高级的 Python 概念。以此为契机学习。它远非完美(例如,它缺少一些非常基本的错误检查和处理),但它是一个很好的起点。

class Pizza:
    size_mappings = {
        1: "Small",
        2: "Large",
        3: "Extra Large",
        4: "Party Size"
    }
    cost_mappings = {
        "Small": 6.23,
        "Large": 10.23,
        "Extra Large": 12.23,
        "Party Size": 24.23
    }
    cost_per_topping = 1.23
    topping_mappings = {
        1: 'Bacon',
        2: 'Pepperoni',
        3: 'Mushrooms',
        4: 'Anchovies',
        5: 'Spinach',
        6: 'Onions',
        7: 'Black Olives',
        8: 'Chicken',
        9: 'Ground Beef'
    }
    size_menu = """
        What size pizza would you like?
            
            1: Small         ${Small}
            2: Large         ${Large}
            3: Extra Large   ${Extra Large} 
            4: Party Size    ${Party Size}\n\n"""

    def __init__(self, size_wanted, requested_toppings):
        self.size_wanted = size_wanted
        self.requested_toppings = requested_toppings

    def finalize_order(self):
        cost = self.cost_mappings[self.size_mappings[self.size_wanted]] + len(self.requested_toppings) * self.cost_per_topping
        print("Thanks for ordering. The final cost is {}".format(cost))

    @classmethod
    def show_size_menu(cls):
        return cls.size_menu.format(**cls.cost_mappings)

    @classmethod
    def show_toppings_menu(cls):
        return "What toppings would you want on your Pizza?\n{}".format(
            '\n'.join('{}: {}'.format(k, v) for k, v in cls.topping_mappings.items())
        )

    @classmethod
    def from_user_input(cls):
        size_wanted = int(input(cls.show_size_menu()))
        requested_toppings = []
        print(cls.show_toppings_menu())
        print("Type requested toppings' numbers, and 'q' when done")
        while True:
            req_topping = input()
            if req_topping == 'q':
                break
            try:
                requested_toppings.append(int(req_topping))
            except ValueError:
                print('Only numbers or q')
        return cls(size_wanted, requested_toppings)


p = Pizza.from_user_input()
p.finalize_order()

好处:

  1. 所有常量值都在一个位置,就在class Pizza. 如果我们需要改变某些东西,我们确切地知道它在哪里。

  2. 该类Pizza与创建方法解耦,并不依赖于我们每次创建实例时都以正确的顺序调用 5 个方法。

  3. 如果明天有人要求我们从 json 文件创建一个Pizza,那只是实现def from_json_file.

上述代码的示例执行:

What size pizza would you like?
            
            1: Small         $6.23
            2: Large         $10.23
            3: Extra Large   $12.23 
            4: Party Size    $24.23

2
What toppings would you want on your Pizza?
1: Bacon
2: Pepperoni
3: Mushrooms
4: Anchovies
5: Spinach
6: Onions
7: Black Olives
8: Chicken
9: Ground Beef
Type requested toppings' numbers, and 'q' when done
1
3
7
q
Thanks for ordering. The final cost is 13.92

推荐阅读