【问题标题】:Is there a way to call a Python code in Excel-VBA?有没有办法在 Excel-VBA 中调用 Python 代码?
【发布时间】:2017-07-31 07:58:56
【问题描述】:

我有一个包含宏的 Excel 文件 (Main.xlsm)。我有一个 Python 文件 (python.py) 来生成一个辅助 Excel 文件 (sub.xlsx),我将在 Main.xlsm 文件的宏中进一步调用它。这个由 py​​thon.py 运行生成的 sub.xlsx 文件保存在同一工作目录中。

现在我想让这个 python.py 在 Main.xlsm 宏运行期间执行,然后使用这个 xlsx 文件。我基本上是想减少外部执行 python.py 的步骤。有这个命令吗?我是 VBA 新手。

【问题讨论】:

  • 然后保持新的(和远离)VBA :) 我希望你能找到你需要的东西。有趣的问题。
  • @Jean-FrançoisFabre 感谢您对问题的关注。 :p
  • 从我的角度来看(也适用于其他专有和繁琐的系统),有时最好 1) 将数据导出为 CSV 2) 运行 python 脚本来轻松处理数据 3) 重新导入到excel/whatever 所以我们也使用这个技巧而不是尝试用子语言编写代码:)
  • 我使用“网关类”。之所以称为网关,是因为它向 Excel VBA 开发人员打开了 Python 生态系统的丰富世界exceldevelopmentplatform.blogspot.com/2018/06/…
  • 我已经添加了一个完整的答案(用一个不同的例子)。

标签: python vba excel


【解决方案1】:

最简单的方法是使用Shell 命令运行python 解释器

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

【讨论】:

  • 感谢您的回复@Uri。但一个小问题是它是 python 还是 VBA 的命令?我需要在 VBA 中执行它。
  • @UriGoren yourscript 根据这个上下文是 Main.xlsm?
  • 不,这是你的 python 脚本文件名
  • 您可能还需要使用您的python 解释器的完整路径,以防您的PATH 没有它
【解决方案2】:

是的,有。我首选的方法是通过 xlwings (https://www.xlwings.org/),但还有其他几个选项。 XlWings 很棒,因为它是免费的、开源的、易于使用的,并且有很好的文档。不过有一些功能限制,因此您必须检查它是否符合您的需求。

【讨论】:

  • 好主意,点个赞。 XlWings 不是在单线程中工作吗?
  • 很棒的插件!不知道这个,谢谢!有一个(其他)赞成票。
  • 当然我会检查@Gabor。感谢您的回复。
  • @Bathsheba Support for threading 最近已添加到 xlwings。
【解决方案3】:

有多种方法可以使用 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

【讨论】:

  • 非常好 - 如果可以的话,我会更加赞成。
【解决方案4】:

我有一个完整的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

这里的好处是没有炮击。当它返回的代码时,你就知道它已经完成了,脱壳一次必须检查脱壳过程是否已经结束等等。这个网关类要好得多恕我直言。

【讨论】:

  • 有趣的提议!但是,如果我错了,请纠正我,但是现在您要启动两个进程(python 脚本,然后是 Excel),对吗?
  • @Joel:如果是两个进程,那将与脱壳相同。但是,如果位数相同,则将 python 运行时 dll 加载到 Excel.exe 中。如果位数不同,那么是的,有两个过程,这是我对该主题的调查exceldevelopmentplatform.blogspot.com/2018/06/…
  • ModuleNotFoundError: 没有名为“win32com”的模块
  • @drgs 没有名为“xyz”的模块意味着您需要安装“xyz”。
  • @SMeaden 运行您的代码后,我收到此错误:TypeError: Can't locate the script hosting the COM object - please set _reg_class_spec_ in your object。我还尝试使用test1.py --register 在cmd 中注册相同的内容。然后我得到一个模块未找到 NumPy 的错误。虽然我已经安装了 NumPy。你能帮帮我吗?
猜你喜欢
  • 2013-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-16
  • 1970-01-01
相关资源
最近更新 更多