Bootstrap

Python第十三次课堂作业(类和对象):商品类

题目

在这里插入图片描述

入门

正所谓能跑得起来运行不出错、达到作业要求就好了

# 创建一个商品类,有:管理人员姓名、密码、商品编号、商品名称、进货单价、销售单价、销售折扣、库存共8个属性,
# 方法有:身份验证、修改商品名称、修改进货价、修改单价、修改折扣、修改库存、显示商品基础信息。
# 使用这个类创建三个对象。
# 要求:当执行:修改商品名称、修改进货价、修改单价、修改折扣、修改库存方法的时候需要身份验证。
# 显示商品显示除了进货价外的其他属性。

class Goods:
    def __init__(self, username: str, password: str,
                 goods_id: str, goods_name: str, purchase_price: float,
                 sale_price: float, discount: float, stock: int):
        self.username = username  # 管理人员姓名
        self.password = password  # 管理人员密码
        self.goods_id = goods_id  # 商品编号
        self.goods_name = goods_name  # 商品名称
        self.purchase_price = purchase_price  # 进货单价 单位:元
        self.sale_price = sale_price  # 销售单价 单位:元
        self.discount = discount  # 销售折扣 0.0~1.0
        self.stock = stock  # 库存 单位:件

        # 额外变量:
        self.isLogin = False  # 是否登录

    def login(self, username: str, password: str) -> bool:
        """身份验证,需要管理员验证"""
        if self.username == username and self.password == password:
            self.isLogin = True
            return True
        else:
            # 登录失败就重置登录状态
            self.isLogin = False
            return False

    def modify_goods_name(self, goods_name: str):
        """修改商品名称,需要管理员验证"""
        if not self.isLogin:
            return False
        # 商品名称不能为None和空
        if goods_name is not None and goods_name != "":
            self.goods_name = goods_name
            return True
        self.goods_name = goods_name
        return True

    def modify_purchase_price(self, purchase_price: float):
        """修改进货价,需要管理员验证"""
        if not self.isLogin:
            return False
        # 进货价不能为负数
        if purchase_price >= 0:
            self.purchase_price = purchase_price
            return True
        else:
            return False

    def modify_sale_price(self, sale_price: float):
        """修改单价,需要管理员验证"""
        if not self.isLogin:
            return False
        # 单价不能为负数
        if sale_price >= 0:
            self.sale_price = sale_price
            return True
        else:
            return False

    def modify_discount(self, discount: float):
        """修改折扣,需要管理员验证"""
        if not self.isLogin:
            return False
        # 折扣范围 0.0~1.0
        if 0.0 <= discount <= 1.0:
            self.discount = discount
            return True
        else:
            return False

    def modify_stock(self, stock: int):
        """修改库存,需要管理员验证"""
        if not self.isLogin:
            return False
        # 库存不能为负数
        if stock >= 0:
            self.stock = stock
            return True
        else:
            return False

    def show_info(self):
        """显示商品基础信息"""
        print(
            f"商品编号:{self.goods_id},商品名称:{self.goods_name},销售单价:{self.sale_price}元,销售折扣:{self.discount},库存:{self.stock}件")

    def show_all_info(self):
        """显示商品所有信息,需要管理员验证"""
        if not self.isLogin:
            return False

        print(
            f"商品编号:{self.goods_id},商品名称:{self.goods_name},进货单价:{self.purchase_price}元,销售单价:{self.sale_price}元,销售折扣:{self.discount},库存:{self.stock}件")
        return True


if __name__ == '__main__':
    goodsList = [
        Goods("admin1", "123456", "001", "苹果", 5.0, 10.0, 0.8, 100),
        Goods("admin2", "123456", "002", "香蕉", 2.0, 5.0, 0.9, 200),
        Goods("admin3", "123456", "003", "橘子", 3.0, 6.0, 0.8, 300)
    ]

    goodsIdList = [goods.goods_id for goods in goodsList]
    menuList = ["1.显示商品信息", "2.修改商品名称", "3.修改进货价", "4.修改单价", "5.修改折扣", "6.修改库存",
                "7.显示商品的所有信息", "8.退出/切换商品"]

    while True:
        # 打印商品信息
        print("\n商品信息如下:")
        for goods in goodsList:
            goods.show_info()
        print("——————————————————————")
        # 选择商品
        goods_id = input("请输入你要操作的商品的编号(输入q则退出):")
        if goods_id == "":
            print(" - 您没有输入商品编号!")
            continue

        if goods_id == "q":
            print(" - 退出程序!")
            break

        if goods_id not in goodsIdList:
            print(" - 您输入的商品编号不存在!")
            continue

        # 选择商品
        goodsIndex = goodsIdList.index(goods_id)  # 获取商品索引
        goods = goodsList[goodsIndex]  # 获取商品对象
        print(f" - 您选择的商品是:{goods.goods_name}")

        # 选择操作
        while True:
            print("\n请选择你要进行的操作:")
            for menu in menuList:
                print(menu)
            print("——————————————————————")
            option = input("请输入你要进行的操作:")
            if option == "":
                print(" - 您没有输入操作!")
                continue

            try:
                if option == "1":
                    print(" - 显示商品信息!")
                    goods.show_info()
                    continue
                elif option == "2":
                    print(" - 修改商品名称!")
                    new_goods_name = input("请输入新的商品名称:")
                    if goods.modify_goods_name(new_goods_name):
                        print(" - 修改商品名称成功!")
                        continue
                    else:
                        print(" - 修改商品名称失败!")
                elif option == "3":
                    print(" - 修改进货价!")
                    new_purchase_price = input("请输入新的进货价:")
                    if goods.modify_purchase_price(float(new_purchase_price)):
                        print(" - 修改进货价成功!")
                        continue
                    else:
                        print(" - 修改进货价失败!")
                elif option == "4":
                    print(" - 修改单价!")
                    new_sale_price = input("请输入新的单价:")
                    if goods.modify_sale_price(float(new_sale_price)):
                        print(" - 修改单价成功!")
                        continue
                    else:
                        print(" - 修改单价失败!")
                elif option == "5":
                    print(" - 修改折扣!")
                    new_discount = input("请输入新的折扣:")
                    if goods.modify_discount(float(new_discount)):
                        print(" - 修改折扣成功!")
                        continue
                    else:
                        print(" - 修改折扣失败!")
                elif option == "6":
                    print(" - 修改库存!")
                    new_stock = input("请输入新的库存:")
                    if goods.modify_stock(int(new_stock)):
                        print(" - 修改库存成功!")
                        continue
                    else:
                        print(" - 修改库存失败!")
                elif option == "7":
                    print(" - 显示商品的所有信息!")
                    if goods.show_all_info():
                        print(" - 显示商品的所有信息成功!")
                        continue
                    else:
                        print(" - 显示商品的所有信息失败!")
                elif option == "8":
                    print(" - 退出/切换商品!")
                    break
                else:
                    print(" - 您输入的操作不存在!")
                    continue

                # 这里对上述操作失败进行一个判断,如果是未登录则进行登录
                if not goods.isLogin:
                    print(" - 请先登录!")
                    retryTimes = 3
                    for i in range(retryTimes):
                        username = input("请输入用户名:")
                        password = input("请输入密码:")
                        if goods.login(username, password):
                            print(" - 登录成功!")
                            break
                        else:
                            print(" - 登录失败!你还有", retryTimes - i - 1, "次机会!")
                            continue
            except Exception as e:
                print(f" - 操作失败!{e}")
                continue

进阶

通过这个示例,我们可以学到:

  1. 将一个商品类拆成管理员类和商品类,便于逻辑上对题目进行拆解。
  2. 通过 @property 装饰器,可以将方法变成属性进行访问。
  3. 使用 @classmethod 装饰器,对成员变量进行递增,有记忆性,用于生成goods_id递增。
  4. 使用 @staticmethod 装饰器,将类中的方法单独出来作为静态方法,处理类另外的操作。
# 创建一个商品类,有:管理人员姓名、密码、商品编号、商品名称、进货单价、销售单价、销售折扣、库存共8个属性,
# 方法有:身份验证、修改商品名称、修改进货价、修改单价、修改折扣、修改库存、显示商品基础信息。
# 使用这个类创建三个对象。
# 要求:当执行:修改商品名称、修改进货价、修改单价、修改折扣、修改库存方法的时候需要身份验证。
# 显示商品显示除了进货价外的其他属性。
import random


# 管理员类
class Admin:
    __username = None
    __password = None
    __isLogin = False

    def __init__(self, username, password):
        self.__username = username
        self.__password = password

    def verify(self, username, password):
        if username == self.__username and password == self.__password:
            self.__isLogin = True
            return True
        else:
            # 一旦登录失败,就将登录状态重置为False,防止多次登录失败后,登录状态仍然为True
            self.__isLogin = False
            return False

    # 通过 @property 装饰器,可以将方法变成属性进行访问。但限制只能读取,不能修改。
    @property
    def isLogin(self):
        return self.__isLogin


class Goods:
    __admin = None
    __goods_id = 0  # 商品编号
    __goods_name = None  # 商品名称
    __purchase_price = None  # 进货单价 单位:元
    __sale_price = None  # 销售单价 单位:元
    __discount = None  # 销售折扣 0.0~1.0
    __stock = None  # 库存 单位:件
    __errMsg = None  # 收集错误信息

    def __init__(self, username: str, password: str,
                 goods_name: str, purchase_price: float,
                 sale_price: float, discount: float, stock: int):

        self.__goods_id = self.id_number()  # 递增商品编号
        self.set_goods_name(goods_name)  # 商品名称
        self.set_purchase_price(purchase_price)  # 进货单价 单位:元
        self.set_sale_price(sale_price)  # 销售单价 单位:元
        self.set_discount(discount)  # 销售折扣 0.0~1.0
        self.set_stock(stock)  # 库存 单位:件

        self.__errMsg = ""

        # 对于Goods对象的调用者来说,不需要知道其内部的Admin对象,所以将其设置为私有属性,仅内部使用
        self.__admin = Admin(username, password)

    # 使用 @classmethod 装饰器,对goods_id进行递增,有记忆性
    @classmethod
    def id_number(cls):
        cls.__goods_id = str(int(cls.__goods_id) + 1).zfill(3)
        # 向前补0,补三位
        return cls.__goods_id

    def getIsLogin(self):
        return self.__admin.isLogin

    def login(self, username, password):
        return self.__admin.verify(username, password)

    @staticmethod
    def loginByRetry(goods, retry_times=3):
        """可多次试错的登录接口,设置重试次数,默认为3次"""
        if goods.getIsLogin():
            # 已经登录过了,无需再次登录
            return True

        print(" - 请先登录!")
        for i in range(retry_times):
            username = input("请输入用户名:")
            password = input("请输入密码:")
            if goods.login(username, password):
                print(" - 登录成功!")
                return True
            else:
                print(" - 登录失败!你还有", retry_times - i - 1, "次机会!")
                continue
        return False

    @property
    def errMsg(self):
        return self.__errMsg

    @property
    def goods_id(self):
        return self.__goods_id

    def get_goods_name(self):
        return self.__goods_name

    def set_goods_name(self, goods_name: str):
        """修改商品名称,需要管理员验证"""
        if self.__goods_name and (not self.loginByRetry(self)):
            # 如果属性已经被赋值,代表此操作不为初始化,是二次修改,需要验证身份
            self.__errMsg = "登录失败!账号或密码错误!"
            return False
        # 商品名称不能为None和空
        if goods_name is not None and goods_name != "":
            self.__goods_name = goods_name
            return True
        else:
            self.__errMsg = "商品名称不能为空!"
            return False

    def get_purchase_price(self):
        return self.__purchase_price

    def set_purchase_price(self, purchase_price: float):
        """修改进货价,需要管理员验证"""
        if self.__purchase_price and (not self.loginByRetry(self)):
            # 如果属性已经被赋值,代表此操作不为初始化,是二次修改,需要验证身份
            self.__errMsg = "登录失败!账号或密码错误!"
            return False
        # 进货价不能为负数
        if purchase_price >= 0:
            self.__purchase_price = purchase_price
            return True
        else:
            self.__errMsg = "进货价不能为负数!"
            return False

    def get_sale_price(self):
        return self.__sale_price

    def set_sale_price(self, sale_price: float):
        """修改单价,需要管理员验证"""
        if self.__sale_price and (not self.loginByRetry(self)):
            # 如果属性已经被赋值,代表此操作不为初始化,是二次修改,需要验证身份
            self.__errMsg = "登录失败!账号或密码错误!"
            return False
        # 单价不能为负数
        if sale_price >= 0:
            self.__sale_price = sale_price
            return True
        else:
            self.__errMsg = "单价不能为负数!"
            return False

    def get_discount(self):
        return self.__discount

    def set_discount(self, discount: float):
        """修改折扣,需要管理员验证"""
        if self.__discount and (not self.loginByRetry(self)):
            # 如果属性已经被赋值,代表此操作不为初始化,是二次修改,需要验证身份
            self.__errMsg = "登录失败!账号或密码错误!"
            return False
        # 折扣范围 0.0~1.0
        if 0.0 <= discount <= 1.0:
            self.__discount = discount
            return True
        else:
            self.__errMsg = "折扣不能为负数!"
            return False

    def get_stock(self):
        return self.__stock

    def set_stock(self, stock: int):
        """修改库存,需要管理员验证"""
        if self.__stock and (not self.loginByRetry(self)):
            # 如果属性已经被赋值,代表此操作不为初始化,是二次修改,需要验证身份
            self.__errMsg = "登录失败!账号或密码错误!"
            return False
        # 库存不能为负数
        if stock >= 0:
            self.__stock = stock
            return True
        else:
            self.__errMsg = "单价不能为负数!"
            return False

    def show_info(self):
        """显示商品基础信息"""
        print(
            f"商品编号:{self.__goods_id},商品名称:{self.__goods_name},销售单价:{self.__sale_price}元,"
            f"销售折扣:{self.__discount},库存:{self.__stock}件")

    def show_all_info(self):
        """显示商品所有信息,需要管理员验证"""
        if not self.loginByRetry(self):
            self.__errMsg = "登录失败!账号或密码错误!"
            return False
        print(
            f"商品编号:{self.goods_id},商品名称:{self.get_goods_name()},进货单价:{self.get_purchase_price()}元,"
            f"销售单价:{self.get_sale_price()}元,销售折扣:{self.get_discount()},库存:{self.get_stock()}件"
        )
        return True

    @staticmethod
    def showAllGoods(goods):
        """显示所有商品信息"""
        # 格式化输出
        print("{0:<10}{1:<10}{2:<10}{3:<10}{4:<10}".format("商品编号", "商品名称", "销售单价",
                                                           "销售折扣", "库存"))
        for good in goods:
            print(
                "{0:<13}{1:<13}{2:<12}{3:<12}{4:<12}".format(good.goods_id, good.get_goods_name(),
                                                             good.get_sale_price(),
                                                             good.get_discount(), good.get_stock()))

        print("————————————————————————")


if __name__ == '__main__':
    goodsList = [
        Goods("admin1", "123456", "苹果", 5.0, 10.0, 0.8, 100),
        Goods("admin2", "123456", "香蕉", 2.0, 5.0, 0.9, 200),
        Goods("admin3", "123456", "橘子", 3.0, 6.0, 0.8, 300)
    ]

    # 商品id数组:用于判断用户输入的目标商品id是否存在于商品列表中
    goodsIdList = [goods.goods_id for goods in goodsList]

    # 菜单列表
    menuList = [
        "1.显示商品信息",
        "2.修改商品名称",
        "3.修改进货价",
        "4.修改单价",
        "5.修改折扣",
        "6.修改库存",
        "7.显示商品的所有信息",
        "8.退出/切换商品"
    ]

    while True:
        # 打印商品信息
        print("\n商品信息如下:")
        Goods.showAllGoods(goodsList)
        # 选择商品
        goods_id = input("请输入你要操作的商品的编号(输入q则退出):")
        if goods_id == "":
            print(" - 您没有输入商品编号!")
            continue

        if goods_id == "q":
            print(" - 退出程序!")
            break

        if goods_id not in goodsIdList:
            print(" - 您输入的商品编号不存在!")
            continue

        # 选择商品
        goodsIndex = goodsIdList.index(goods_id)  # 获取商品索引
        goods = goodsList[goodsIndex]  # 获取商品对象
        print(f" - 您选择的商品是:{goods.get_goods_name()}")

        # 选择操作
        while 1:
            # 打印菜单
            print("\n请选择你要进行的操作:")
            for menu in menuList:
                print(menu)
            print("——————————————————————")
            option = input("请输入你要进行的操作:")
            if option == "":
                print(" - 您没有输入操作!")
                continue

            try:
                if option == "1":
                    print(" - 显示商品信息!")
                    goods.show_info()
                    continue
                elif option == "2":
                    print(" - 修改商品名称!")
                    new_goods_name = input("请输入新的商品名称:")
                    if goods.set_goods_name(new_goods_name):
                        print(" - 修改商品名称成功!")
                    else:
                        print(" - 修改商品名称失败!" + goods.errMsg)
                elif option == "3":
                    print(" - 修改进货价!")
                    new_purchase_price = input("请输入新的进货价:")
                    if goods.set_purchase_price(float(new_purchase_price)):
                        print(" - 修改进货价成功!")
                    else:
                        print(" - 修改进货价失败!" + goods.errMsg)
                elif option == "4":
                    print(" - 修改单价!")
                    new_sale_price = input("请输入新的单价:")
                    if goods.set_sale_price(float(new_sale_price)):
                        print(" - 修改单价成功!")
                    else:
                        print(" - 修改单价失败!" + goods.errMsg)
                elif option == "5":
                    print(" - 修改折扣!")
                    new_discount = input("请输入新的折扣:")
                    if goods.set_discount(float(new_discount)):
                        print(" - 修改折扣成功!")
                    else:
                        print(" - 修改折扣失败!" + goods.errMsg)
                elif option == "6":
                    print(" - 修改库存!")
                    new_stock = input("请输入新的库存:")
                    if goods.set_stock(int(new_stock)):
                        print(" - 修改库存成功!")
                    else:
                        print(" - 修改库存失败!" + goods.errMsg)
                elif option == "7":
                    print(" - 显示商品的所有信息!")
                    if goods.show_all_info():
                        print(" - 显示商品的所有信息成功!")
                    else:
                        print(" - 显示商品的所有信息失败!")
                elif option == "8":
                    print(" - 退出/切换商品!")
                    break
                else:
                    print(" - 您输入的操作不存在!")
                    continue
            except Exception as e:
                print(f" - 操作失败!{e}")
                continue

高阶

本例包含三个类,分别为:商品类、管理员类、仓库类(聚合商品和管理员的类)
其中商品类和管理员类为Dao层,仓库类为控制层(Controller)
通过本例我可以学习到:

  1. 如何使用装饰器,以及装饰器的使用场景
  2. 对类的属性进行封装(私有化),以及通过@property对属性进行修改的方法
  3. 使用@classmethod装饰器,实现对类静态变量(goods_id)的递增操作,以及对类的实例化操作
  4. 使用@staticmethod装饰器,实现对类的静态方法的调用
  5. 使用@wraps装饰器,实现对被装饰器修饰的类的方法进行功能添加,例如登录验证,异常捕获等
  6. 学习定义并使用自定义装饰器:无参装饰器,有参装饰器。
  7. 设计模式的简单尝试。
# 作者:刘海
# 博客:https://blog.csdn.net/s1711323390/article/details/127834177
# 时间:2022年11月15日

# 题目:
# 创建一个商品类,有:管理人员姓名、密码、商品编号、商品名称、进货单价、销售单价、销售折扣、库存共8个属性,
# 方法有:身份验证、修改商品名称、修改进货价、修改单价、修改折扣、修改库存、显示商品基础信息。
# 使用这个类创建三个对象。
# 要求:当执行:修改商品名称、修改进货价、修改单价、修改折扣、修改库存方法的时候需要身份验证。
# 显示商品显示除了进货价外的其他属性。
from functools import wraps


# 本例包含五个类,分别为:商品类、管理员类、仓库类(聚合商品和管理员的类)、自定义装饰器工具类、错误信息类
# 其中商品类和管理员类为Dao层,仓库类为控制层(Controller)
# 通过本例我可以学习到:
# 1.如何使用装饰器,以及装饰器的使用场景
# 2.对类的属性进行封装(私有化),以及通过@property对属性进行修改的方法
# 3.使用@classmethod装饰器,实现对类静态变量(goods_id)的递增操作,以及对类的实例化操作
# 4.使用@staticmethod装饰器,实现对类的静态方法的调用
# 5.使用@wraps装饰器,实现对被装饰器修饰的类的方法进行功能添加,例如登录验证,异常捕获等
# 6.学习定义并使用自定义装饰器:无参装饰器,有参装饰器。
# 7.设计模式的简单尝试。


# 管理员类:该类主要用于对管理员信息的查询等操作,为Dao层
class Admin:
    def __init__(self, username: str, password: str):
        self.__username = username  # 管理员用户名
        self.__password = password  # 管理员密码
        self.__isLogin = False  # 管理员登录状态

    def verify(self, username: str, password: str):
        if username == self.__username and password == self.__password:
            # 登录成功,修改登录状态标记为True
            self.__isLogin = True
            return True
        else:
            # 一旦登录失败,就将登录状态重置为False,防止多次登录失败后,登录状态仍然为True
            self.__isLogin = False
            return False

    # 通过 @property 装饰器,可以将方法变成属性进行访问。但限制只能读取,不能修改。
    # 例如可以通过 admin.isLogin 来读取admin内部私有变量__isLogin的值
    @property
    def isLogin(self):
        return self.__isLogin


# 商品类:该类主要用于对商品的基本信息进行修改,为Dao层。
class Goods:
    __goods_id: str = "000"  # 商品编号

    def __init__(self,
                 goods_name: str, purchase_price: float,
                 sale_price: float, discount: float, stock: int):

        # 这里设置goods_id时,使用self.id_number()方法,使用@classmethod装饰器。
        # 这样每次创建对象时,都会自动调用该方法,在上一个创建对象的id的基础上递增id:001 002 003
        self.__goods_id = self.id_number()  # 递增商品编号

        # 以下赋值操作,表面上是直接赋值,其实底层已经通过@xxx.setter装饰器,调用了对应的赋值方法
        # 这样做的好处是,可以在赋值时,进行一些额外的操作,比如传入的参数是否合法。
        self.__goods_name = goods_name  # 商品名称
        self.__purchase_price = purchase_price  # 进货单价 单位:元
        self.__sale_price = sale_price  # 销售单价 单位:元
        self.__discount = discount  # 销售折扣 0.0~1.0
        self.__stock = stock  # 库存 单位:件

    # 使用 @classmethod 装饰器,对goods_id进行递增,有记忆性
    @classmethod
    def id_number(cls):
        # 向前补0,补三位,比如:001 002 003
        cls.__goods_id = str(int(cls.__goods_id) + 1).zfill(3)
        return cls.__goods_id

    @property
    def goods_id(self):
        return self.__goods_id

    @property
    def goods_name(self):
        return self.__goods_name

    # 通过 @xxx.setter 装饰器,可以将赋值操作变成方法进行调用。类似于修改底层的赋值操作。
    @goods_name.setter
    def goods_name(self, goods_name: str):
        """修改商品名称,需要管理员验证"""
        # 商品名称不能为None和空
        if goods_name is None or goods_name == "":
            raise ValueError(ErrorType.ParamsError("商品名称不能为空"))
        self.__goods_name = goods_name

    @property
    def purchase_price(self):
        return self.__purchase_price

    @purchase_price.setter
    def purchase_price(self, purchase_price: float):
        """修改进货价,需要管理员验证"""
        # 进货价不能为负数
        if purchase_price < 0:
            raise ValueError(ErrorType.ParamsError("进货价不能为负数"))
        self.__purchase_price = purchase_price

    @property
    def sale_price(self):
        return self.__sale_price

    @sale_price.setter
    def sale_price(self, sale_price: float):
        """修改单价,需要管理员验证"""
        # 单价不能为负数
        if sale_price < 0:
            raise ValueError(ErrorType.ParamsError("单价不能为负数"))
        self.__sale_price = sale_price

    @property
    def discount(self):
        return self.__discount

    @discount.setter
    def discount(self, discount: float):
        """修改折扣,需要管理员验证"""
        # 折扣范围 0.0~1.0
        if 0.0 <= discount <= 1.0:
            self.__discount = discount
        else:
            raise ValueError(ErrorType.ParamsError("折扣范围 0.0~1.0"))

    @property
    def stock(self):
        return self.__stock

    @stock.setter
    def stock(self, stock: int):
        """修改库存,需要管理员验证"""
        # 库存不能为负数
        if stock < 0:
            raise ValueError(ErrorType.ParamsError("库存不能为负数"))
        self.__stock = stock


# 错误信息类,用来规范化raise抛出的的错误信息
class ErrorType:
    def __init__(self, code, msg):
        self.code = code
        self.msg = msg

    @staticmethod
    def ParamsError(errMsg):
        return ErrorType(1001, "参数错误:" + errMsg)

    @staticmethod
    def LoginError(errMsg):
        return ErrorType(1002, "登录失败:" + errMsg)

    def __str__(self):
        return f"错误码:{self.code}, 错误信息 - {self.msg}"


# 自定义装饰器工具类
class CustomDecoratorUtils:
    # 以下两个函数为自定义装饰器,在调用被装饰器修饰的方法时,会走这两个装饰器函数。
    # 用于对原本函数进行功能添加,例如在设置商品属性前,要进行登录验证,那么装饰器就用于登录验证
    @staticmethod
    def verify_admin(retry_times=3):
        """装饰器:调用func函数前进行管理员验证,有retry_times次重试机会"""

        def outer(func):
            @wraps(func)
            def inner(self, *args, **kwargs):
                """可多次试错的登录接口,设置重试次数,默认为3次"""
                if self.isLogin():
                    # 已经登录过了,无需再次登录,直接调用目标函数
                    return func(self, *args, **kwargs)

                print(" - 请先登录!你有{}次机会.".format(retry_times))
                for i in range(retry_times):
                    _username = input("请输入用户名:")
                    _password = input("请输入密码:")
                    if self.login(_username, _password):
                        print(" - 登录成功!")
                        # 登录成功后调用执行目标方法
                        return func(self, *args, **kwargs)
                    else:
                        print(" - 登录失败!你还有", retry_times - i - 1, "次机会!")
                        continue
                raise ValueError(ErrorType.LoginError("账号或密码错误!"))

            return inner

        return outer

    @staticmethod
    def modify_catch_errors(func):
        """装饰器:该函数用于在运行func函数时若报错,则捕获异常"""

        # 这里主要用于捕获当用户设置属性时,若属性值不符合要求,函数会抛出异常,被该装饰器捕获。
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            try:
                func(self, *args, **kwargs)
                print(" - 修改信息成功!")
            except ValueError as _e:
                print(" - 修改信息失败!", _e)

        return wrapper


# 仓库类,该类为工厂类,属于控制层(Controller)逻辑,给用户进行逻辑层交互。
class GoodsManage:
    __admin: Admin  # 管理员类
    __goods: Goods  # 商品类

    def __init__(self, admin: Admin, goods: Goods):
        # 通过该 __init 方法,将管理员类和商品类传入仓库类中
        self.__admin = admin
        self.__goods = goods

    # 也可以通过另一种构造方法实例化对象
    @classmethod
    def createByDetails(cls, username: str, password: str,
                        goods_name: str, purchase_price: float,
                        sale_price: float, discount: float, stock: int):
        # 这种方式可以通过将零散的属性值传入,构造出一个完整的对象
        admin = Admin(username, password)
        goods = Goods(goods_name, purchase_price, sale_price, discount, stock)
        return cls(admin, goods)

    # 通过 @modify_catch_errors 这个自定义装饰器,可以在设置商品属性时,若属性值不符合要求,函数会抛出异常,被该装饰器捕获。
    # 通过 @verify_admin 这个自定义装饰器,可以在设置商品属性前,要进行登录验证,那么该装饰器就用于登录验证。
    # 先装饰 @modify_catch_errors 让它包裹在最外层,再装饰 @verify_admin 让它被包裹在里面,也被catch装饰器捕获。
    @CustomDecoratorUtils.modify_catch_errors
    @CustomDecoratorUtils.verify_admin(retry_times=2)
    def modify_goods_name(self, goods_name: str):
        """修改商品名称"""
        self.__goods.goods_name = goods_name

    @CustomDecoratorUtils.modify_catch_errors
    @CustomDecoratorUtils.verify_admin(retry_times=2)
    def modify_purchase_price(self, purchase_price: float):
        """修改进货价"""
        self.__goods.purchase_price = purchase_price

    @CustomDecoratorUtils.modify_catch_errors
    @CustomDecoratorUtils.verify_admin(retry_times=2)
    def modify_sale_price(self, sale_price: float):
        """修改单价"""
        self.__goods.sale_price = sale_price

    @CustomDecoratorUtils.modify_catch_errors
    @CustomDecoratorUtils.verify_admin(retry_times=2)
    def modify_discount(self, discount: float):
        """修改折扣"""
        self.__goods.discount = discount

    @CustomDecoratorUtils.modify_catch_errors
    @CustomDecoratorUtils.verify_admin(retry_times=2)
    def modify_stock(self, stock: int):
        """修改库存"""
        self.__goods.stock = stock

    # 获取商品id
    def get_goods_id(self):
        return self.__goods.goods_id

    # 获取商品名称
    def get_goods_name(self):
        return self.__goods.goods_name

    # 获取进货价
    def get_purchase_price(self):
        return self.__goods.purchase_price

    # 获取销售单价
    def get_sale_price(self):
        return self.__goods.sale_price

    # 获取折扣
    def get_discount(self):
        return self.__goods.discount

    # 获取库存
    def get_stock(self):
        return self.__goods.stock

    # 判断是否登录
    def isLogin(self):
        return self.__admin.isLogin

    def login(self, username: str, password: str):
        return self.__admin.verify(username, password)

    def show_goods_info(self):
        """显示商品基础信息或包含库存信息"""
        print("商品信息如下:")
        print(" - 商品编号:", self.get_goods_id())
        print(" - 商品名称:", self.get_goods_name())
        print(" - 单价:%.2f 元" % self.get_sale_price())
        print(" - 折扣:%.2f 折" % self.get_discount())
        print(" - 库存:%.2f 件" % self.get_stock())

    # 不设置重试次数,那么默认为 3 次
    @CustomDecoratorUtils.verify_admin(retry_times=2)
    def show_all_info(self):
        """显示商品所有信息(包含库存),需要管理员验证"""
        self.show_goods_info()
        print(" - 进货价:%.2f元" % self.get_purchase_price())

    @staticmethod
    def showAllGoods(gmList: list):
        """显示所有商品的信息,gmList为GoodsManage类对象列表"""
        print("商品信息如下:")
        # 格式化输出
        print("{0:<10}{1:<10}{2:<10}{3:<10}{4:<10}".format("商品编号", "商品名称", "销售单价",
                                                           "销售折扣", "库存"))
        for goodsManageItem in gmList:
            # 左对齐,保留2位小数
            print(
                "{0:<13}{1:<12}{2:<12.2f}{3:<12.2f}{4:<12.2f}".format(
                    goodsManageItem.get_goods_id(),
                    goodsManageItem.get_goods_name(),
                    goodsManageItem.get_sale_price(),
                    goodsManageItem.get_discount(),
                    goodsManageItem.get_stock())
            )

        print("————————————————————————")


if __name__ == '__main__':
    goodsManageList = [
        # 可以通过类初始化方法 __init__ 创建对象
        GoodsManage(Admin("admin1", "123456"), Goods("苹果", 5.0, 10.0, 0.8, 100)),
        GoodsManage(Admin("admin2", "123456"), Goods("香蕉", 2.0, 5.0, 0.9, 200)),
        # 也可以通过类方法 @classmethod 创建对象
        GoodsManage.createByDetails("admin3", "123456", "橘子", 3.0, 6.0, 0.8, 300),
    ]

    # 商品id数组:用于判断用户输入的目标商品id是否存在于商品列表中
    goodsIdList = [goods.get_goods_id() for goods in goodsManageList]

    # 菜单列表
    menuList = [
        "1.显示商品信息",
        "2.修改商品名称",
        "3.修改进货价",
        "4.修改单价",
        "5.修改折扣",
        "6.修改库存",
        "7.显示商品的所有信息",
        "8.退出/切换商品"
    ]

    while True:
        # 打印商品信息
        GoodsManage.showAllGoods(goodsManageList)
        # 选择商品
        goods_id = input("请输入你要操作的商品的编号(输入q则退出):")
        if goods_id == "":
            print(" - 您没有输入商品编号!")
            continue

        if goods_id == "q":
            print(" - 退出程序!")
            break

        if goods_id not in goodsIdList:
            print(" - 您输入的商品编号不存在!")
            continue

        # 选择商品
        goodsIndex = goodsIdList.index(goods_id)  # 获取商品索引
        goodsManageItem = goodsManageList[goodsIndex]  # 获取商品对象
        print(f" - 您选择的商品是:{goodsManageItem.get_goods_name()}")

        # 选择操作
        while 1:
            # 打印菜单
            print("\n请选择你要进行的操作:")
            for menu in menuList:
                print(menu)
            print("——————————————————————")
            option = input("请输入你要进行的操作:")
            if option == "":
                print(" - 您没有输入操作!")
                continue

            try:
                option = int(option)
                if option == 1:
                    print(" - 显示商品信息!")
                    goodsManageItem.show_goods_info()
                elif option == 2:
                    print(" - 修改商品名称!")
                    new_goods_name = input("请输入新的商品名称:")
                    goodsManageItem.modify_goods_name(new_goods_name)
                elif option == 3:
                    print(" - 修改进货价!")
                    new_purchase_price = input("请输入新的进货价:")
                    goodsManageItem.modify_purchase_price(float(new_purchase_price))
                elif option == 4:
                    print(" - 修改单价!")
                    new_sale_price = input("请输入新的单价:")
                    goodsManageItem.modify_sale_price(float(new_sale_price))
                elif option == 5:
                    print(" - 修改折扣!")
                    new_discount = input("请输入新的折扣:")
                    goodsManageItem.modify_discount(float(new_discount))
                elif option == 6:
                    print(" - 修改库存!")
                    new_stock = input("请输入新的库存:")
                    goodsManageItem.modify_stock(int(new_stock))
                elif option == 7:
                    print(" - 显示商品的所有信息!")
                    goodsManageItem.show_all_info()
                elif option == 8:
                    print(" - 退出/切换商品!")
                    break
                else:
                    print(" - 您输入的操作不存在!")
            except Exception as e:
                print(f" - 操作失败!请检查你输入的内容:{e}")

;