我在Microsoft Access中有一个VBA脚本.VBA脚本是具有多个人的大型项目的一部分,因此无法离开VBA环境.
在我的脚本的一部分中,我需要快速地在桌面上进行复杂的线性代数.因此,我将编写为记录集的VBA表移动到Python中以执行线性代数,然后返回到VBA.python中的矩阵表示为numpy数组.
一些线性代数是专有的,因此我们使用pyinstaller编译专有脚本.
该过程的细节如下:
input.csv.input.csv作为numpy矩阵加载,对其执行线性代数,并创建输出csv文件output.csv. output.csv. input.csv文件和output.csv文件.这个过程效率低下.
有没有办法在没有csv混乱的情况下将VBA矩阵加载到Python(和后面)?这些方法是否可以通过pyinstaller使用已编译的python代码?
我在stackoverflow上找到了以下相关的示例.但是,它们没有具体解决我的问题.
检索运行Access的COM实例并通过COM API直接使用python脚本获取/设置数据:
VBA:
Private Cache
Public Function GetData()
GetData = Cache
Cache = Empty
End Function
Public Sub SetData(data)
Cache = data
End Sub
Sub Usage()
Dim wshell
Set wshell = VBA.CreateObject("WScript.Shell")
' Make the data available via GetData()'
Cache = Array(4, 6, 8, 9)
' Launch the python script compiled with pylauncher '
Debug.Assert 0 = wshell.Run("C:\dev\myapp.exe", 0, True)
' Handle the returned data '
Debug.Assert Cache(3) = 2
End Sub
Run Code Online (Sandbox Code Playgroud)
Python(myapp.exe):
import win32com.client
if __name__ == "__main__":
# get the running instance of Access
app = win32com.client.GetObject(Class="Access.Application")
# get some data from Access
data = app.run("GetData")
# return some data to Access
app.run("SetData", [1, 2, 3, 4])
Run Code Online (Sandbox Code Playgroud)
或者创建一个COM服务器以向Access公开一些功能:
VBA:
Sub Usage()
Dim Py As Object
Set Py = CreateObject("Python.MyModule")
Dim result
result = Py.MyFunction(Array(5, 6, 7, 8))
End Sub
Run Code Online (Sandbox Code Playgroud)
Python(myserver.exe或myserver.py):
import sys, os, win32api, win32com.server.localserver, win32com.server.register
class MyModule(object):
_reg_clsid_ = "{5B4A4174-EE23-4B70-99F9-E57958CFE3DF}"
_reg_desc_ = "My Python COM Server"
_reg_progid_ = "Python.MyModule"
_public_methods_ = ['MyFunction']
def MyFunction(self, data) :
return [(1,2), (3, 4)]
def register(*classes) :
regsz = lambda key, val: win32api.RegSetValue(-2147483647, key, 1, val)
isPy = not sys.argv[0].lower().endswith('.exe')
python_path = isPy and win32com.server.register._find_localserver_exe(1)
server_path = isPy and win32com.server.register._find_localserver_module()
for cls in classes :
if isPy :
file_path = sys.modules[cls.__module__].__file__
class_name = '%s.%s' % (os.path.splitext(os.path.basename(file_path))[0], cls.__name__)
command = '"%s" "%s" %s' % (python_path, server_path, cls._reg_clsid_)
else :
file_path = sys.argv[0]
class_name = '%s.%s' % (cls.__module__, cls.__name__)
command = '"%s" %s' % (file_path, cls._reg_clsid_)
regsz("SOFTWARE\\Classes\\" + cls._reg_progid_ + '\\CLSID', cls._reg_clsid_)
regsz("SOFTWARE\\Classes\\AppID\\" + cls._reg_clsid_, cls._reg_progid_)
regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_, cls._reg_desc_)
regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\LocalServer32', command)
regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\ProgID', cls._reg_progid_)
regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOM', class_name)
regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOMPath', os.path.dirname(file_path))
regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\Debugging', "0")
print('Registered ' + cls._reg_progid_)
if __name__ == "__main__":
if len(sys.argv) > 1 :
win32com.server.localserver.serve(set([v for v in sys.argv if v[0] == '{']))
else :
register(MyModule)
Run Code Online (Sandbox Code Playgroud)
请注意,您必须在没有任何参数的情况下运行脚本一次以注册该类并使其可用VBA.CreateObject.
两种解决方案都可以使用,pylauncher并且可以使用python接收在python中接收的数组numpy.array(data).
依赖性:
https://pypi.python.org/pypi/pywin32