script pyxll python excel vba excel-vba

python - script - pyxll



¿Hay alguna manera de llamar a un código Python en Excel-VBA? (4)

Hay varias formas de ejecutar un script de Python con VBA, dependiendo de si es necesario esperar al final de la ejecución y saber si se realizó sin errores.

Con Shell , asíncrono con consola:

Public Sub RunPython(file As String, ParamArray args()) Shell "python.exe """ & file & """ " & Join(args, " ") End Sub

Con Shell , síncrono sin consola:

Public Function RunPython(file As String, ParamArray args()) Shell "pythonw.exe """ & file & """ " & Join(args, " ") End Function

Con WScript.Shell , síncrono sin consola y con código de salida:

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

Tengo un archivo de Excel (Main.xlsm) que contiene macros. Tengo un archivo de Python (python.py) para generar un archivo de Excel subsidiario (sub.xlsx) que llamaría en las macros del archivo Main.xlsm Este archivo sub.xlsx generado por la ejecución de python.py se guarda en el mismo directorio de trabajo.

Ahora quiero hacer que este python.py se ejecute durante la ejecución de las macros Main.xlsm y luego use este archivo xlsx. Básicamente quiero reducir el paso de ejecutar python.py externamente. ¿Hay un comando para eso? Soy nuevo en VBA.


Sí hay. Mi forma preferida de hacer esto es a través de xlwings ( https://www.xlwings.org/ ), pero también hay varias otras opciones. XlWings es genial porque es gratuito, de código abierto y fácil de usar, con excelente documentación. Sin embargo, hay algunas limitaciones de funciones, por lo que tendría que verificar si se ajusta a sus necesidades.


Tuve un mes completo de Python en mi blog aquí . Establezco un patrón al que llamo la clase de puerta de enlace que es una clase Python habilitada para COM, se registrará si se ejecuta desde la línea de comandos y una vez registrada se crea una instancia con CreateObject ("foo.bar").

Aquí hay un buen ejemplo de VBA llamando a una clase de Python que usa algunas funciones de 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)

y el código VBA de llamada

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

El comentario completo se puede encontrar en la entrada del blog original aquí

La ventaja aquí es que no hay bombardeos. Cuando el código que devuelve, usted sabe que ha terminado, con el bombardeo una vez tiene que verificar si el proceso de shell ha finalizado, etc. Esta clase de puerta de enlace es mucho mejor que la de mi trabajo.


La forma más sencilla es ejecutar el intérprete de Python con el comando Shell

Shell ("python.exe " & yourScript & " " & arguments)