游客发表

我修复了Pandas包的一个bug

发帖时间:2025-11-05 04:56:33

你好,修复我是修复zhenguo,今天说个开心事~  

1. 还原这个bug

导出含有层级关系的修复列头时,会多写出一个空行,修复此bug稳定出现。修复

2. 定位问题

经过调试发现,修复锁定此bug出现的修复位置到excel.py模块,如下所示:

理一理excel.py模块封装的修复方法,经过调试发现,修复write方法中下面几行代码是修复关键逻辑:

写入到excel过程,实际是修复逐个单元格写入到excel过程,主要调用封装的修复get_formatted_cells方法得到formatted_cells。

formatted_cells = self.get_formatted_cells()

writer.write_cells(

formatted_cells,修复

sheet_name,

startrow=startrow,

startcol=startcol,

freeze_panes=freeze_panes,

)

再进去看看get_formatted_cells方法,它使用chain串接了两个生成器,修复然后逐一yield吐出cell:

def get_formatted_cells(self):

for cell in itertools.chain(self._format_header(),修复 self._format_body()):

cell.val = self._format_value(cell.val)

yield cell

而串接的这两个迭代器,一个是self._format_header(),另一个是self._format_body()。

经过调试,在这里就能找到bug出现的原因,云服务器提供商self._format_body()是有问题的,经过格式化数据域部分。拿文章一开始的case举例,取值为a的单元格对应的行索引被错误的标记为3,注意行索引是从0开始的。很明显,实际应该是2。

3. 修复bug

找到原因后,进一步下钻到底层方法,经过调试,进一步锁定到self._format_body()中调用的 _format_regular_rows方法,里面与行编号相关联的属性是self.rowcounter,所以重点关注与它相关的写入逻辑:

def _format_regular_rows(self):

has_aliases = isinstance(self.header, (tuple, list, np.ndarray, Index))

if has_aliases or self.header:

self.rowcounter += 1

# output index and index_label?

if self.index:

# check aliases

# if list only take first as this is not a MultiIndex

if self.index_label and isinstance(

self.index_label, (list, tuple, np.ndarray, Index)

):

index_label = self.index_label[0]

# if string good to go

elif self.index_label and isinstance(self.index_label, str):

index_label = self.index_label

else:

index_label = self.df.index.names[0]

if isinstance(self.columns, ABCMultiIndex):

self.rowcounter += 1

一共有2处可能的写入,其中第二处写入,也就是服务器托管上面代码块的最后两行,是bug出现的原因。经过仔细分析,在级联表头(ABCMultiIndex)写入excel场景中,行索引已经在self._format_header()中,行索引已经被加1,所以再在此处对其加1,是重复的:

if isinstance(self.columns, ABCMultiIndex):

self.rowcounter += 1

所以修改方法就是对其标注即可。

4. 修复bug后

修复后,经过测试级联列头、单列头,都正常,不再有多余的空行。

以上,此bug我已经提交到github的pandas中,希望帮助到更多的开发者。

我是zhenguo,最后希望点赞+转发~

    热门排行

    友情链接