我有一个包含宏的Excel文件(Main.xlsm)。我有一个Python文件(python.py)来生成一个辅助Excel文件(sub.xlsx),我将在Main.xlsm文件的宏中进一步调用它。这个由python.py运行生成的sub.xlsx文件保存在同一个工作目录中。
现在我想让这个python.py在Main.xlsm宏运行期间执行,然后使用这个xlsx文件。我基本上想要减少外部执行python.py的步骤。那是否有命令?我是VBA的新手。
答案 0 :(得分:26)
最简单的方法是使用Shell
命令
Shell ("python.exe " & yourScript & " " & arguments)
答案 1 :(得分:19)
是的,有。我这样做的首选方法是通过xlwings(https://www.xlwings.org/),但也有其他一些选项。 XlWings很棒,因为它是免费的,开源的,易于使用的,具有出色的文档。但是有一些功能限制,所以你必须检查它是否符合你的需要。
答案 2 :(得分:15)
使用VBA运行python脚本有多种方法,具体取决于您是否需要等待执行结束并知道它是否没有错误。
使用Shell,与控制台异步:
Public Sub RunPython(file As String, ParamArray args())
Shell "python.exe """ & file & """ " & Join(args, " ")
End Sub
使用Shell,同步不使用控制台:
Public Function RunPython(file As String, ParamArray args())
Shell "pythonw.exe """ & file & """ " & Join(args, " ")
End Function
使用WScript.Shell,同步不使用控制台并使用退出代码:
Public Function RunPython(file As String, ParamArray args()) As Long
Dim obj As Object
Set obj = CreateObject("WScript.Shell")
RunPython = obj.Run("pythonw.exe """ & file & """ " & Join(args, " "), 0, True)
End Function
答案 3 :(得分:0)
我有整个Python month on my blog right here。我建立了一个模式,称为网关类,它是一个启用COM的Python类,如果从命令行运行,它将注册自己,并且一旦注册就会用CreateObject(“ foo.bar”)实例化。
这是VBA调用使用某些scipy函数的Python类的一个很好的例子
import numpy as np
import pandas as pd
from scipy.stats import skewnorm
class PythonSkewedNormal(object):
_reg_clsid_ = "{1583241D-27EA-4A01-ACFB-4905810F6B98}"
_reg_progid_ = 'SciPyInVBA.PythonSkewedNormal'
_public_methods_ = ['GeneratePopulation', 'BinnedSkewedNormal']
def GeneratePopulation(self, a, sz):
# https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.random.seed.html
np.random.seed(10)
# https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.stats.skewnorm.html
return skewnorm.rvs(a, size=sz).tolist()
def BinnedSkewedNormal(self, a, sz, bins):
# https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.random.seed.html
np.random.seed(10)
# https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.stats.skewnorm.html
pop = skewnorm.rvs(a, size=sz)
bins2 = np.array(bins)
bins3 = pd.cut(pop, bins2)
table = pd.value_counts(bins3, sort=False)
table.index = table.index.astype(str)
return table.reset_index().values.tolist()
if __name__ == '__main__':
print("Registering COM server...")
import win32com.server.register
win32com.server.register.UseCommandLine(PythonSkewedNormal)
和调用VBA代码
Option Explicit
Sub TestPythonSkewedNormal()
Dim skewedNormal As Object
Set skewedNormal = CreateObject("SciPyInVBA.PythonSkewedNormal")
Dim lSize As Long
lSize = 100
Dim shtData As Excel.Worksheet
Set shtData = ThisWorkbook.Worksheets.Item("Sheet3") '<--- change sheet to your circumstances
shtData.Cells.Clear
Dim vBins
vBins = Array(-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5)
'Stop
Dim vBinnedData
vBinnedData = skewedNormal.BinnedSkewedNormal(-5, lSize, vBins)
Dim rngData As Excel.Range
Set rngData = shtData.Cells(2, 1).Resize(UBound(vBins) - LBound(vBins), 2)
rngData.Value2 = vBinnedData
'Stop
End Sub
完整的评论可以在原始的blog entry here
中找到这里的优点是没有脱壳。当代码返回时,您就知道它已经完成了,一次脱壳必须检查脱壳过程是否已结束等。此网关类要好得多,恕我直言。