尽管Excel面临着来自免费软件(如OpenOffice)和云服务(如Google Sheets)的挑战,它仍然是办公环境中最广泛使用的用户友好型计算和数据处理应用程序。能够从Excel调用Python代码极大地扩展了Excel的功能,利用了Python丰富的库和强大的语言特性。
ExcelPython是一个进程内的COM库,它允许加载Python模块、调用方法和操作对象。与其他Python/Excel接口(如PyXLL和Python-Excel)相比,ExcelPython在一些微妙之处有所不同,因此具有稍微不同的适用领域。ExcelPython的优势在于它是免费的(无论是成本还是许可证)、小巧轻便、高度可嵌入:可以使用打包的Python发行版,以便在不安装Python的情况下分发电子表格,对最终用户透明:Python是从Excel VBA调用启动的,因此一旦开发了电子表格代码,就不需要额外的用户干预,通用性:可以调用任何现有的Python模块或函数,并操作任何Python对象,实际上ExcelPython可以用来直接调用Python库,而不需要编写任何额外的Python代码来包装它们。
如果想了解如何使用库提供的函数的非常基础的教程,请访问Sourceforge上的ExcelPython页面,在wiki部分有一个分步指南供开始。
在这个教程中,将看看如何使用ExcelPython合并一系列列表,对它们的值进行排序并删除任何重复项。在Python中,这是一个非常简单的任务,只需要几行代码,而等效的VBA代码会更冗长一些。
def merge_sort_unique(lists):
s = set()
for L in lists:
s.update(L)
return sorted(s)
在所选择的位置创建一个新文件夹,并将此脚本保存在名为Methods.py的文件中。
启动Excel,首先制作一些将传递给Python脚本的输入数据,并将工作簿保存在与Python脚本相同的文件夹中。工作表应该看起来像这样:
要打开VBA,请按Alt+F11,然后转到“工具”|“引用...”,如果正确安装了ExcelPython,应该能够在对话框中选择它。
要检查现在是否可以引用ExcelPython库,请尝试在立即窗口(如果它不可见,按Ctrl+G)中输入?PyVar(PyEval("1+2")),应该看到结果。
现在准备调用Python方法。创建一个新模块(插入|模块)并编写以下VBA代码:
Function msu(lists As Range)
Set methods = PyModule("Methods", AddPath:=ThisWorkbook.Path)
Set result = PyCall(methods, "merge_sort_unique", PyTuple(lists.Value2))
msu = WorksheetFunction.Transpose(PyVar(result))
Exit Function
End Function
让逐行查看这段代码。
Set methods = PyModule("Methods", AddPath:=ThisWorkbook.Path)
这个语句相当于Python中的import Methods。在这里加载Methods模块,它在Methods.py中定义,遵循Python模块的名称是它们定义的文件或文件夹名称的约定,并将它们存储在VBA的methods变量中。这意味着现在VBA函数有一个名为methods的局部变量,它实际上指向Python模块对象。注意AddPath参数,它使能够在尝试加载模块之前将额外的文件夹插入到Python路径的开头 - 在这种情况下,添加包含工作簿的文件夹,以便它找到Methods.py文件。
Set result = PyCall(methods, "merge_sort_unique", PyTuple(lists.Value2))
ExcelPython的PyCall方法接受一个有序参数列表,使用PyTuple方法构建,可选地接受一个关键字参数列表,可以使用PyDict方法构建。在这里,结果存储在VBA的result变量中。
result变量现在指向一个Python列表对象,因此不能直接放入工作表中(会发生类型错误)。因此,作为最后一步,使用PyVar方法将Python列表对象转换为VBA数组。
msu = WorksheetFunction.Transpose(PyVar(result))
PyVar方法通用地将Python对象转换为它们的VBA等效物,如果可能的话,可以选择转换Python列表列表到2D数组的维度。更多详细信息可以在ExcelPython的Sourceforge wiki中找到。
在工作表中创建一个数组块(通过选择多个单元格,输入公式并按Ctrl-Shift-Enter),公式为=msu(A1:C16)。应该看到以下结果:
如果没有,那么不用担心,ExcelPython非常容易调试。对VBA代码进行以下修改:
Function msu(lists As Range)
On Error GoTo do_error
Set methods = PyModule("Methods", AddPath:=PyPath)
Set result = PyCall(methods, "merge_sort_unique", PyTuple(lists.Value2))
msu = WorksheetFunction.Transpose(PyVar(result))
Exit Function
do_error:
msu = Err.Description
End Function
这样任何错误都会被捕捉并在工作表上显示,可以分析出了什么问题。
这实际上是Python的None对象被粘贴到工作表的结果。为什么函数返回的合并元素中包含None?
def merge_sort_unique(lists):
s = set()
for L in lists:
s.update(L)
s.remove(None)
return sorted(s)