我有一个包含宏的Excel文件(Main.xlsm)。 我有一个Python文件(python.py)来生成一个辅助Excel文件(sub.xlsx),我将在Main.xlsm文件的宏中进一步调用它。 这个由python.py运行生成的sub.xlsx文件保存在同一个工作目录中。
现在我想让这个python.py在Main.xlsm宏运行期间执行,然后使用这个xlsx文件。 我基本上想要减少外部执行python.py的步骤。 那是否有命令? 我是VBA的新手。
-
然后保持新的(并远离)VBA :)我希望你找到你需要的。 有趣的问题。
-
@ Jean-FranoisFabre感谢您对问题的关注。:p
-
从我的角度来看(也适用于其他专有和繁琐的系统),有时最好1)以CSV格式导出数据2)运行python脚本以便轻松处理数据3)重新导入excel / what所以我们也使用这个 技巧,而不是尝试在子语言中编码:)
-
我使用'网关类'。 所谓的网关,因为它打开了Excel生态系统的丰富世界到Excel VBA Developer exceldevelopmentplatform.blogspot.com/2018/06/
-
我添加了一个完整的答案(使用不同的例子)。
最简单的方法是使用Shell命令运行python解释器
1
| Shell ('python.exe' & yourScript &'' & arguments) |
-
谢谢你的回复@Uri。但是一个小问题是它是python或VBA的命令吗?我需要在VBA中执行它。
-
这是一个VBA命令
-
@UriGoren yourscript根据这个上下文是Main.xlsm?
-
不,这是你的python脚本文件名
-
您可能还需要使用python解释器的完整路径,以防您没有它PATH
就在这里。我首选的方法是通过xlwings(https://www./),但也有其他几个选项。 XlWings很棒,因为它是免费的,开源的,易于使用的,具有出色的文档。但是有一些功能限制,因此您必须检查它是否符合您的需求。
-
好主意,有一个upvote。不是XlWings在单个线程中工作吗?
-
据我所知,它确实是单线程的
-
伟大的加载项!不知道这一个,谢谢!有(其他)upvote。
-
我肯定会检查@Gabor。感谢您的答复。
-
@Bathsheba最近在xlwings中添加了对线程的支持。
-
@Xukrao,谢谢你指出这一点,这是个好消息。
使用VBA运行python脚本有多种方法,具体取决于您是否需要等待执行结束并知道它是否没有错误。
使用Shell,与控制台异步:
1 2 3
| Public Sub RunPython(file As String, ParamArray args())
Shell'python.exe''' & file &'''' & Join(args,'')
End Sub |
使用Shell,无需控制台同步:
1 2 3
| Public Function RunPython(file As String, ParamArray args())
Shell'pythonw.exe''' & file &'''' & Join(args,'')
End Function |
使用WScript.Shell,无需控制台同步和退出代码:
1 2 3 4 5
| 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 |
我的博客上有一整个Python月份。我建立了一个模式,我称之为网关类,它是一个支持COM的Python类,如果从命令行运行,它将注册自己,并且一旦使用CreateObject('foo.bar')实例化注册。
这是VBA调用Python类的一个很好的例子,它使用了一些scipy函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 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./doc/numpy-1.15.1/reference/generated/numpy.random.seed.html
np.random.seed(10)
# https://docs./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./doc/numpy-1.15.1/reference/generated/numpy.random.seed.html
np.random.seed(10)
# https://docs./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代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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 |
完整的评论可以在这里的原始博客条目中找到
这里的优点是没有炮击。当它返回的代码时,你知道它已经完成了,炮击一旦检查炮轰进程是否已经结束等等。这个网关类是更好的恕我直言。
-
有趣的提议!但是,如果我错了,请纠正我,但现在你有两个启动进程(python脚本,然后是Excel),对吗?
-
@Joel:如果是两个进程,那么与shelling相同。但是,如果位数相同,则将python运行时dll加载到Excel.exe中。如果位数不同那么肯定有两个过程,这是我对该主题的调查exceldevelopmentplatform.blogspot.com/2018/06/
-
ModuleNotFoundError:没有名为'win32com'的模块
-
@drgs没有名为'xyz'的模块意味着您需要安装'xyz'。
|