修復(fù)了Pandas包的一個bug
這篇文章介紹Pandas中一個bug,昨天研究了此bug出現(xiàn)的原因,及修改措施。感興趣的可以看一下,獲取在日后能對你有一定幫助。
1 還原這個bug
導(dǎo)出含有層級關(guān)系的列頭時,會多寫出一個空行,此bug穩(wěn)定出現(xiàn)。
2 定位問題
經(jīng)過調(diào)試發(fā)現(xiàn),鎖定此bug出現(xiàn)的位置到excel.py模塊,如下所示:
理一理excel.py模塊封裝的方法,經(jīng)過調(diào)試發(fā)現(xiàn),write方法中下面幾行代碼是關(guān)鍵邏輯:
????????formatted_cells?=?self.get_formatted_cells()
????????
????????writer.write_cells(
????????????formatted_cells,
????????????sheet_name,
????????????startrow=startrow,
????????????startcol=startcol,
????????????freeze_panes=freeze_panes,
????????)
寫入到excel過程,實(shí)際是逐個單元格寫入到excel過程,主要調(diào)用封裝的get_formatted_cells方法得到formatted_cells
再進(jìn)去看看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()
經(jīng)過調(diào)試,在這里就能找到bug出現(xiàn)的原因,self._format_body()是有問題的,經(jīng)過格式化數(shù)據(jù)域部分。拿文章一開始的case舉例,取值為a的單元格對應(yīng)的行索引被錯誤的標(biāo)記為3,注意行索引是從0開始的。很明顯,實(shí)際應(yīng)該是2
3 修復(fù)bug
找到原因后,進(jìn)一步下鉆到底層方法,經(jīng)過調(diào)試,進(jìn)一步鎖定到self._format_body()中調(diào)用的 _format_regular_rows方法,里面與行編號相關(guān)聯(lián)的屬性是self.rowcounter,所以重點(diǎn)關(guān)注與它相關(guān)的寫入邏輯:
????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出現(xiàn)的原因。經(jīng)過仔細(xì)分析,在級聯(lián)表頭(ABCMultiIndex)寫入excel場景中,行索引已經(jīng)在self._format_header()中,行索引已經(jīng)被加1,所以再在此處對其加1,是重復(fù)的:
????????????if?isinstance(self.columns,?ABCMultiIndex):
????????????????self.rowcounter?+=?1
所以修改方法就是對其標(biāo)注即可。
4 修復(fù)bug后
修復(fù)后,經(jīng)過測試級聯(lián)列頭、單列頭,都正常,不再有多余的空行。
以上,此bug我已經(jīng)提交到github的pandas中,希望幫助到更多的開發(fā)者。
對比Excel系列圖書累積銷量達(dá)15w冊,讓你輕松掌握數(shù)據(jù)分析技能,可以在全網(wǎng)搜索書名進(jìn)行了解選購:




