Ответ 1
Самый простой способ - запустить интерпретатор python с помощью команды Shell
Shell ("python.exe " & yourScript & " " & arguments)
У меня есть файл Excel (Main.xlsm), содержащий макросы. У меня есть файл Python (python.py) для создания вспомогательного файла Excel (sub.xlsx), который я бы далее назвал в макросах файла Main.xlsm. Этот sub.xlsx файл, который генерируется при запуске python.py, сохраняется в том же рабочем каталоге.
Теперь я хочу, чтобы этот python.py выполнялся во время выполнения макросов Main.xlsm, а затем использовал этот xlsx файл. Я в основном хочу уменьшить шаг выполнения Python.py извне. Есть ли команда для этого? Я новичок в VBA.
Самый простой способ - запустить интерпретатор python с помощью команды Shell
Shell ("python.exe " & yourScript & " " & arguments)
Да, есть. Мой предпочтительный способ сделать это через xlwings (https://www.xlwings.org/), но есть и другие варианты. XlWings отличная, потому что она бесплатна, с открытым исходным кодом и проста в использовании, с отличной документацией. Однако есть некоторые ограничения по функциям, поэтому вам нужно будет проверить, соответствует ли оно вашим потребностям.
Существует несколько способов запустить скрипт Python с VBA в зависимости от того, нужно ли вам ждать окончания выполнения и знать, прошло ли оно без ошибок.
С 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
У меня был целый месяц Python в моем блоге прямо здесь. Я устанавливаю шаблон, который я называю классом шлюза, который является классом Python с поддержкой COM, он будет регистрироваться сам при запуске из командной строки и после регистрации создается с помощью CreateObject ("foo.bar").
Вот хороший пример VBA, вызывающей класс Python, который использует некоторые функции scipy
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
Полный комментарий можно найти в оригинальной записи в блоге здесь.
Преимущество здесь в том, что обстрела нет. Когда код возвращается, вы знаете, что он закончился, при обстреле один раз нужно проверить, завершился ли процесс шелла и т.д. Этот класс шлюза намного лучше ИМХО.