属性错误:无法为工作簿设置属性。

7

我有以下代码,我正在写入一个已经存在的Excel文件:

book = load_workbook(file_path)
writer = pd.ExcelWriter(file_path, engine = 'openpyxl')
writer.book = book
writer.sheets = dict((ws.title, ws) for ws in book.worksheets)

我在这一行遇到了错误:

writer.book = book as

该行代码与书写格式不符合,可能会导致程序出错。
writer.book = book

AttributeError: can't set attribute

更糟糕的是,这个错误发生在我的同事的Mac电脑上,但是在我的Windows电脑上没有出现。有什么想法吗?

3个回答

7

我在运行1.5.0版本时遇到了与@bella相同的问题,但在运行1.4.4版本时并没有遇到此问题。我在1.5.0版本的发布说明中找到了以下内容。

ExcelWriter的所有属性以前都被记录为不公开的。然而,一些第三方Excel引擎记录了访问ExcelWriter.bookExcelWriter.sheets等属性,并且用户正在使用这些属性及可能的其他属性。以前,这些属性是不安全的;例如,修改ExcelWriter.book不会更新ExcelWriter.sheets,反之亦然。为了支持这一点,pandas已经使一些属性变成了公开的,并改进了它们的实现,使它们现在可以安全地使用。(GH45572

以下属性现在是公开的,并被认为是安全可访问的。

  • book
  • check_extension
  • close
  • date_format
  • engine
  • if_sheet_exists
  • sheets
  • supported_extensions

以下属性已被弃用。当访问时,它们现在会引发一个FutureWarning,并将在未来的版本中删除。用户应该知道它们的使用是不安全的,并可能导致意外的结果。

  • cur_sheet
  • handles
  • path
  • save
  • write_cells

编辑:

所以经过很多(很多)努力后,我找到了一个对我有效的解决方案,也可能对其他人有用。

此处所述,Pandas团队的哲学是使book(和sheets)的设置器为私有,并将这些责任推给实现Excel引擎的程序。

对我有效的解决方案是使用Python将模板Excel文件复制到新文件中,例如:

import shutil

output_path = shutil.copy(template_path, output_path)
  • 然后,在实例化ExcelWriter时将output_path作为工作簿加载。因此,根本不需要调用openpyxl.load_workbook(),也不需要复制.book.sheets属性。
  • 此外,请确保按以下方式设置modeif_sheet_exists标志(有关更多信息,请参见文档):
writer = pd.ExcelWriter(
    output_path,
    engine="openpyxl",
    mode="a",
    if_sheet_exists="overlay",
)
  • 最后,一定要删除所有对 book 的引用(如果您之前有任何引用),这是我遇到的一个特别微妙的 bug。我的代码修改表格、定义名称、引用等工作簿内的内容时,将其应用于由 openpyxl.load_workbook() 返回的工作簿实例变量 book 上。然后,将该变量分配给 ExcelWriter 实例的 book 属性,方法是使用以下代码:writer.book = book,与您刚才做的一样。但是,这只是对内存中相同对象的引用,因此修改 bookExcelWriter.book 具有相同的效果,而我的代码碰巧在 book 上执行。但是,如果您进行了上述更改,则不再需要修改 book 变量,而是直接使用 writer.book 与工作簿进行交互,例如:writer.book.defined_names.get(defined_name).attr_text = ref,而不是 book.defined_names.get(defined_name).attr_text = ref

希望这能帮到您。


那么我猜它不适用于新版本,但适用于旧版本? - Bella
@Bella,你原来问题中的代码将来将无法使用。Pandas已经明确表示不允许直接访问“book”和“sheets”。我已经编辑了我的原始回答,并提供了一个简单的解决方案,适用于我自己的情况,并且不依赖于任何正在被弃用的私有方法或设置器。 - m12t

4
我发现关键是在这里的代码中使用 writer.workbook 而不是 writer.book:
writer.workbook = openpyxl.load_workbook('test.xlsx')
并且在 pd.ExcelWriter 中添加选项:
mode='a',if_sheet_exists='overlay'
import pandas as pd
import openpyxl
import warnings

warnings.simplefilter(action='ignore', category=FutureWarning)

# create new excel file
df_empty = pd.DataFrame()
df_empty.to_excel('test.xlsx')

# ... with a sheet name
workbook = openpyxl.load_workbook('test.xlsx')
ex_sheet = workbook['Sheet1']
ex_sheet.title = 'Tmp'
workbook.save('test.xlsx')

# prepare a dataframe
df = pd.DataFrame({'Column1': ['aa', 'bb', 'cc', 'dd'],
                   'Column2': [100, 170, 140, 160]})

# insert a dataframe into an excel sheet
writer = pd.ExcelWriter('test.xlsx', engine='openpyxl', mode='a', if_sheet_exists='overlay')
writer.workbook = openpyxl.load_workbook('test.xlsx')
df.to_excel(writer, sheet_name='Tmp', index=False, header=True, startrow=3, startcol=3)

writer.save()

我使用Python 3.8;openpyxl 版本为 3.0.10;pandas 版本为 1.5.0。


0

使用“pip list”在每台机器上双重检查你的依赖版本。我曾经遇到过同样的问题,它是由于每台机器上的pandas版本不同所引起的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接