python - 使用 xlwings 排序 (pywin32)

标签 python python-3.x excel pywin32 xlwings

我需要使用 Python 按给定行对 Excel 电子表格进行排序。为了进行测试,我使用了这些数据(在名为 xlwings sorting.xlsx 的文件中):

Numbers Letters Letters_2
7   A   L
6   B   K
5   C   M
4   D   J
3   E   N
2   F   I
1   G   H

应该归类为:

Numbers Letters Letters_2
1   G   H
2   F   I
3   E   N
4   D   J
5   C   M
6   B   K
7   A   L

人们会认为这是一项微不足道的任务,但在 xlwings 中似乎没有任何文档(如果有的话,它被埋得太深了,两天的阅读都没有发现它)有关列排序的文档或 pywin32

我在网上能找到的最接近的东西是 this question ,它没有答案,只是重定向到一个没有解决方案的 github 错误线程。

不过,我还是设法根据提问者的代码拼凑了以下代码:

import xlwings as xw
from xlwings.constants import SortOrder

bk = xw.Book(r'C:\Users\username\Documents\Test Files\xlwings sorting.xlsx')

sht = bk.sheets['Sheet1']

def xl_col_sort(sht,col_num):
    sht.range('a2').api.Sort(sht.range((2,col_num)).api,SortOrder.xlAscending)
    return

xl_col_sort(sht,1)

这会运行,但我不知道语法是如何工作的。我什至不知道为什么第一个 range('a2') 调用是必要的,但如果我尝试直接调用 sht.api.Sort 它会抛出异常。我试着用 ipython 的 ?? 直接查看代码功能,但它只给我 <xlwings._xlwindows.COMRetryObjectWrapper object at 0x0000001375A459E8> 没有文档字符串。然后,我尝试通过 Sort() 函数的 .py 文件实际按 ctrl+F,但在大量 COM 包装器中遇到了死胡同,无法找到包含该函数的实际模块。

无论如何,即使我不知道测试用例是如何工作的;所以下一步是将这个函数放入一个包含 excel 工作簿和工作表的类中,以将该函数用作方法。我重写了代码,既用作方法又采用字符串而不是列号(新列经常添加到工作表的中间,因此数字会经常更改):

class Metrics:

    # self.sheet is a sheet object based on self.book opened with xlwings
    # a bunch of other methods and attributes

    def xl_col_sort(self,col):

        # +2 because excel starts at 1 (+1) and the dataframe self.df
        # uses a data column as the index (+1)
        col_num = np.where(self.df.columns == col)[0][0] + 2

        so = xw.constants.SortOrder

        self.sheet.range('a2').api.Sort(self.sheet.range((2,col_num)).api, so.xlAscending)
        return

我在这里看不到任何功能上的变化。它仍然收到相同的参数,即使它们经过一个额外的步骤来创建。然而尝试运行它会产生 MemoryError :

In[1]:    metrics.xl_col_sort('Exp. Date')
---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-3-f1de8b0e8e98> in <module>()
----> 1 metrics.xl_col_sort('Exp. Date')

C:\Users\username\Documents\Projects\PyBev\pyBev_0-3-1\pybev\metricsobj.py in xl_col_sort(self, col)
    146         so = xw.constants.SortOrder
    147 
--> 148         self.sheet.range('a2').api.Sort(self.sheet.range((2,col_num)).api, so.xlAscending)
    149         return
    150     # def monday_backup(self):
C:\Users\username\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\xlwings\main.py in range(self, cell1, cell2)
    818                 raise ValueError("Second range is not on this sheet")
    819             cell2 = cell2.impl
--> 820         return Range(impl=self.impl.range(cell1, cell2))
    821 
    822     @property
C:\Users\username\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\xlwings\_xlwindows.py in range(self, arg1, arg2)
    576             if 0 in arg1:
    577                 raise IndexError("Attempted to access 0-based Range. xlwings/Excel Ranges are 1-based.")
--> 578             xl1 = self.xl.Cells(arg1[0], arg1[1])
    579         elif isinstance(arg1, numbers.Number) and isinstance(arg2, numbers.Number):
    580             xl1 = self.xl.Cells(arg1, arg2)
C:\Users\username\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\xlwings\_xlwindows.py in __call__(self, *args, **kwargs)
    149         for i in range(N_COM_ATTEMPTS + 1):
    150             try:
--> 151                 v = self._inner(*args, **kwargs)
    152                 t = type(v)
    153                 if t is CDispatch:
C:\Users\username\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\win32com\client\dynamic.py in __call__(self, *args)
    190                 if invkind is not None:
    191                         allArgs = (dispid,LCID,invkind,1) + args
--> 192                         return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None)
    193                 raise TypeError("This dispatch object does not define a default method")
    194 
MemoryError: CreatingSafeArray

有谁知道这个东西的语法是如何工作的,或者为什么它在放入方法时会中断?

最佳答案

事实证明这是一个非常微妙的错误,所以我想我会发布答案,以防有人在一年内用谷歌搜索这个并试图做类似的事情。

简而言之,sheet.range() 方法只接受整数坐标,表达式:

col_num = np.where(self.df.columns == col)[0][0] + 2

产生一个 float 。为什么这会产生 MemoryError 而不是语法错误,这超出了我的理解,但可能是一个疏忽。 The devs do seem to know about it, though.

此外,上述文档中未列出语法,因为它实际上是 VBA 代码,如发现的那样 here. Sort() 方法仅适用于 Range 对象,因此第一个 sht.range() 调用要求。

最后,如果有人想要一个简化的函数来封装所有这些废话:

import xlwings as xw


bk = xw.Book(file_path)
sheet = bk.sheets['Sheet1'] # or whatever the sheet is named

def xl_col_sort(sheet,col_num):
    sheet.range((2,col_num)).api.Sort(Key1=sheet.range((2,col_num)).api, Order1=1)
return

关于python - 使用 xlwings 排序 (pywin32),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45223182/

相关文章:

java - NoClassDefFoundError : javax/xml/stream/XMLStreamException

vba - Application.WorksheetFunction.SumProduct wsf.CountIfs 与 4 个数组

Excel VBA - 在一定范围内插入多列

python - 使用 Qt Designer 创建多屏幕应用程序

python - 1个生产者,1个消费者,只有1条数据要通信,队列是不是有点大材小用了?

Python:如何在正则表达式中保留字母数字英语、拉丁字符?

python-3.x - 在训练用于对象分类/检测的神经网络时,我们如何知道模型收敛了?

python - 为什么 Python 告诉我在随机抽样之前先排序?

python - 如何在 DEAP Python 中为遗传算法设置群体中的特定染色体

python - Pandas - 巨大的内存消耗