首页 > 解决方案 > 单个函数中的 Python 变量范围很奇怪 - 尽管每个对象都是单独实例化的,但所有实例共享相同的对象

问题描述

我正在制作一些将普通表行解析为分层数据结构的函数。

有两个数据类 - ProductInfo :单品,如 T 恤 - OptionInfo :单品选项,如'yellow-XXL'、'blue-XL'

这些都写在单个 xl 表中。像 ProductInfo 头,它作为 ProdctOption 的尾行。所以我决定像某种状态机一样解析它。

  1. 如果 row 是 Single Product,则创建 ProductInfo 的新实例并使用空 List 初始化 ProductInfo.options。

  2. 如果已经遇到 Product(head) 并且当前行是 Option,则推入实例化 ProductInfo 的列表。

  3. 如果再次遇到 Product,则追加 ProductInfo int reulstList

但最终的结果真的很奇怪。所有 ProductInfo 共享它的选项,如果 10 个产品有 100 个选项,则每个产品包含 100 个选项,尽管其中大多数不是它的选项。

它看起来像下面,

  1. 产品 T 恤 -> [('white', 'XL'), ('red', 'XL'), ('rainbow', '270'), ('yellow', '260')]
  2. Product Sneakers -> [('white', 'XL'), ('red', 'XL'), ('rainbow', '270'), ('yellow', '260')] (如你所见, 前 2 个选项是 T 恤,后 2 个选项是运动鞋)

数据类看起来像这样

class OptionInfo:
    def __init__(self, ProductId: int = None, ProductCode: str = None, Barcode: str = None, Color: str = None, Size: str = None, OptionDescription:str = None):
        self.ProductId = ProductId
        self.ProductCode = ProductCode
        self.Barcode = Barcode
        self.Color = Color
        self.Size = Size
        self.OptionDescription = OptionDescription

class ProductInfo:
    def __init__(self, ProductId = None, ProductBaseCode: str = None, ProductBaseBarcode: str = None, HasOption: bool = False, MajorCategory: str = None, MiddleCategory: str = None, MinorCategory: str = None, Gender: str = None, Supplier: str = None, OriginCountry: str = None, ProductName: str = None, TemporaryProductionPrice: float = None, SalesPrice: float = None, OptionList: List['OptionInfo']  = [], PredefinedCategory: str = None):
        self.ProductId = ProductId
        self.ProductBaseCode = ProductBaseCode
        self.ProductBaseBarcode = ProductBaseBarcode
        self.HasOption = HasOption
        self.MajorCategory = MajorCategory
        self.MiddleCategory = MiddleCategory
        self.MinorCategory = MinorCategory
        self.Gender = Gender
        self.Supplier = Supplier
        self.OriginCountry = OriginCountry
        self.ProductName = ProductName
        self.TemporaryProductionPrice = TemporaryProductionPrice
        self.SalesPrice = SalesPrice
        self.OptionList = OptionList
        self.PredefinedCategory = PredefinedCategory

逻辑代码如下

def parseSheet(xlPath: str) -> List['ProductInfo']:
    log('PRODUCT >> Parsing xl for {}'.format(xlPath))
    wb = openpyxl.load_workbook(xlPath)
    ws = wb.active
    resultSet: List['ProductInfo'] = []
    prInfo: ProductInfo = None
    allowOptions: bool = False
    for rownum in range(2, ws.max_row+1):
        if ws.cell(row=rownum, column=CL_ProductName).value == '' or ws.cell(row=rownum, column=CL_ProductName).value is None: break
        isRepr = ws.cell(row=rownum, column=CL_IsRepr).value
        if isRepr is 1 or isRepr == '1':
            if prInfo is not None: 
                resultSet.append(prInfo)
                prInfo = None
                allowOptions = False
            allowOptions = True
            prInfo = ProductInfo(
                ProductBaseCode         =ws.cell(row=rownum, column=CL_ProductCode).value if ws.cell(row=rownum, column=CL_ProductCode).value != '' else None,
                HasOption               =True,
                ProductName             =ws.cell(row=rownum, column=CL_ProductName).value if ws.cell(row=rownum, column=CL_ProductName).value != '' else None,
                TemporaryProductionPrice=float(ws.cell(row=rownum, column=CL_ProdPrice).value) if ws.cell(row=rownum, column=CL_ProdPrice).value != '' and ws.cell(row=rownum, column=CL_ProdPrice).value is not None else 0,
                SalesPrice              =float(ws.cell(row=rownum, column=CL_SalesPrice).value) if ws.cell(row=rownum, column=CL_SalesPrice).value != '' and ws.cell(row=rownum, column=CL_SalesPrice).value is not None else 0,
                PredefinedCategory      =ws.cell(row=rownum, column=CL_PredCategory).value if ws.cell(row=rownum, column=CL_PredCategory).value != '' else None
            )

        elif isRepr == 'isOption':
            if allowOptions is False or prInfo is None:
                raise Exception('Sheet row order seems strange, check please near {}'.format(rownum))
            prInfo.OptionList.append(
                OptionInfo(
                    ProductCode         =ws.cell(row=rownum, column=CL_ProductCode).value if ws.cell(row=rownum, column=CL_ProductCode).value != '' else None,
                    Barcode             =ws.cell(row=rownum, column=CL_Barcode).value if ws.cell(row=rownum, column=CL_Barcode).value != '' else None,
                    OptionDescription   =ws.cell(row=rownum, column=CL_OptionDesc).value if ws.cell(row=rownum, column=CL_OptionDesc).value != '' else None
                )
            )

        elif isRepr is 0 or isRepr == '0':
            if prInfo is not None: 
                resultSet.append(prInfo)
                prInfo = None
                allowOptions = False
            prInfo = ProductInfo(
                ProductBaseCode         =ws.cell(row=rownum, column=CL_ProductCode).value if ws.cell(row=rownum, column=CL_ProductCode).value != '' else None,
                HasOption               =False,
                ProductName             =ws.cell(row=rownum, column=CL_ProductName).value if ws.cell(row=rownum, column=CL_ProductName).value != '' else None,
                TemporaryProductionPrice=float(ws.cell(row=rownum, column=CL_ProdPrice).value) if ws.cell(row=rownum, column=CL_ProdPrice).value != '' and ws.cell(row=rownum, column=CL_ProdPrice).value is not None else 0,
                SalesPrice              =float(ws.cell(row=rownum, column=CL_SalesPrice).value) if ws.cell(row=rownum, column=CL_SalesPrice).value != '' and ws.cell(row=rownum, column=CL_SalesPrice).value is not None else 0,
                PredefinedCategory      =ws.cell(row=rownum, column=CL_PredCategory).value if ws.cell(row=rownum, column=CL_PredCategory).value != '' else None,
                OptionList=[OptionInfo(
                    ProductCode         =ws.cell(row=rownum, column=CL_ProductCode).value if ws.cell(row=rownum, column=CL_ProductCode).value != '' else None,
                    Barcode             =ws.cell(row=rownum, column=CL_Barcode).value if ws.cell(row=rownum, column=CL_Barcode).value != '' else None,
                    OptionDescription   =ws.cell(row=rownum, column=CL_OptionDesc).value if ws.cell(row=rownum, column=CL_OptionDesc).value != '' else None
                )]
            )

        else:
            raise Exception('Invalid repr in sheet {} at {}'.format(isRepr, rownum))
    return resultSet

isRepr决定是Product还是Option,1表示是Product,'isOption'表示是上层Product的option(isRepr为1),0表示是没有option的Product。

我认为,prInfo被怀疑为原因。但我不明白它的可变范围。如何区分变量声明和分配给变量?可能吗?我该如何解决这个问题。我怀疑原因,但不确定为什么会发生。

标签: python

解决方案


推荐阅读