首页 > 解决方案 > Python/Openpyxl 重复数据

问题描述

我正在创建一个程序,使用 python 和 openpyxl 将所有单个引号移动到一个单引号矩阵中,但是当尝试加载模型信息时,它似乎是从第一个引号重复模型。每个报价都是一个单独的 excel 文件,这让我感到困惑,因为我在获取报价信息时没有问题,即名称、日期等,但是每个报价的模型列表都是相同的,而不是从每个报价中提取模型.

数据结构:

class Model:
    SKU = None
    cost = None
    qty = None
    qty_remaining = None

class Quote:
    name = None
    number = None
    start_date = None
    end_date = None

    models = []

从每个报价电子表格中获取数据的函数:

def load_quote(filename):
    quote_wb = load_workbook(filename=filename, data_only=True, read_only=True)
    quote_sheet = quote_wb.active


    quote = Quote()

    quote.number = quote_sheet['A2'].value
    quote.number = quote.number[9:len(quote.number)]

    quote.name = quote_sheet['A3'].value
    quote.name = quote.name[14:len(quote.name)]

    quote.start_date = quote_sheet['A6'].value
    quote.start_date = quote.start_date[14:len(quote.start_date)]

    quote.end_date = quote_sheet['A7'].value
    quote.end_date = quote.end_date[12:len(quote.end_date)]


    for row_vals in quote_sheet.iter_rows(min_row=12, max_row=250, min_col=1, max_col=9, values_only=True):
        model = Model()
        if row_vals[0] is not None:
            model.SKU = row_vals[0]
            model.cost = row_vals[4]
            model.qty = row_vals[6]
            model.qty_remaining = row_vals[8]
            quote.models.append(model)
        else:
            continue
        
    return quote

每个报价的格式相同,报价编号在单元格 A2 中,名称在单元格 A3 中,开始日期在单元格 A4 中,结束日期在单元格 5 中。

从第 12 行到第 250 行是这种格式的每个模型:

| 货号 | 说明 | 成本 | 原始数量 | 使用数量 | 剩余数量 |

我不需要描述或使用的数量,所以我忽略了这些。如果 quote_sheet 变量基于遍历文件夹中的每个文件而发生变化,并且它正在从每个文件中获取所有报价信息,为什么它没有从每个文件中获取模型信息?

不确定函数调用是否有帮助,但这里也是如此:

quotes = []
for file in os.listdir(os.chdir(directory)):
    if file.endswith(".xlsx"):
        quote = load_quote(file)
        quotes.append(quote)

标签: pythonexcelfileopenpyxl

解决方案


Quote和的所有属性Model都在类级别上定义——它们是类属性。类属性在类的所有实例之间共享。

int对于像or这样的不可变数据,这不是问题str,因为通过编写:

q1 = Quote()
q1.name = 'quote_name'

您实际上是在运行时创建了一个绑定到实例的新实例属性 ,这允许实例在您询问其名称时避免查找类属性。nameq1Quote.name

但是,由于Quote.models它是一个可变数据(列表),它在所有Quote. 如果您附加到该列表,则此就地操作将反映在该类的任何实例中。

您可以通过以下简短示例看到此行为:

class Quote:
    name = None
    number = None
    start_date = None
    end_date = None

    models = []

q1 = Quote()
q2 = Quote()
q1.models.append('x')
print(q2.models)  # output: ['x']

解决此问题的最简单方法是Quote.models通过在方法中定义它来转换为适当的实例属性__init__。通过这种方式,每个Quote实例都使用附加到其models属性的唯一、独立的列表来创建:

class Quote:
    name = None
    number = None
    start_date = None
    end_date = None
    
    def __init__(self):
        self.models = []

这应该足以解决您的问题,尽管为了清楚起见,我真的建议将所有类属性从适当的实例属性转换为适当的实例属性QuoteModel


推荐阅读