19、利用 Visual C++ 和 Delphi 扩展与嵌入 Python

利用 Visual C++ 和 Delphi 扩展与嵌入 Python

1. Python 扩展与嵌入概述

Python 成功的因素众多,其中能够在其他语言中扩展和嵌入 Python 是关键因素之一。若 Python 自身无法完成某些任务,而其他语言可以,那么很有可能为该语言构建一个 Python 接口。本文将探讨如何使用 C/C++ 和 Delphi 语言扩展 Python,涵盖以下主题:
- 手动编写 C 语言的 Python 扩展(或编译他人编写的扩展)
- 使用简化包装器和接口生成器(SWIG),方便地将 C 和 C++ 库暴露给 Python 使用
- 在 C++ 应用程序中嵌入 Python 解释器
- 无需 C 编译器即可动态调用 DLL

2. Python 与 Visual C++

2.1 使用 Visual C++ 的原因

在使用 Python 时,使用 Visual C++ 有以下几个原因:
| 原因 | 说明 |
| — | — |
| 从源代码构建 Python | 许多分发 Python 二进制文件的公司希望能够从 C 源代码构建所有内容,并对这些源代码进行控制。 |
| 编写 Python 扩展 DLL | 若有一个有趣的 Python 扩展的源代码,但没有适用于你所使用 Python 版本的 Windows 二进制文件,可使用 Visual C++ 编写。 |
| 使现有 C 或 C++ 库可用于 Python | 可以将现有的 C 或 C++ 库暴露给 Python 使用。 |
| 在 C 或 C++ 应用程序中嵌入 Python | 出于多种原因,可在 C 或 C++ 应用程序中嵌入 Python。 |

2.2 构建时的问题及解决技巧

从源代码构建时会遇到一些问题,如项目间依赖和版本变更问题。为解决这些问题,可采用以下技巧:
- 不在项目文件中指定 Python15.lib、PyWinTypes.lib 或 PythonCOM.lib,通过包含必要的头文件(如 Python.h 或 PyWinTypes.h)来隐式引用所需的 .lib 文件。
- 使用 Microsoft Visual C++ 全局指定 Python 和其他目录,而非按项目指定,这样在升级 Python 时,只需更改 Visual C++ 的目录引用并重新构建所有项目。

2.3 配置 Visual C++ 以构建 Python 或扩展

配置 Visual C++ 的步骤如下:
1. 确定必要的 Python 文件的位置。若安装的是 Python 二进制版本,这些文件可能位于 C:\Program Files\Python\Include 和 C:\Program Files\Python\libs;若从 Python 源存档构建,头文件目录可能类似 Python - 1.5.2\include 和 Python - 1.5.2\pc,库文件位于 Python - 1.5.2\pcbuild。
2. 启动 Microsoft Visual C++。
3. 选择 Tools -> Options -> Directories,下拉 Show Directories For 组合框,选择 Include Files,添加 Python 头文件所在的目录。
4. 再次选择组合框,选择 Library files,并相应地更新目录。
5. 选择 OK 关闭对话框。

2.4 使用 Visual C++ 构建扩展

以一个简单的扩展模块为例,创建一个名为 spam 的模块,并暴露一个名为 system() 的函数,该函数可运行 DOS 命令。以下是源代码:

/* spammodule.c - pasted from Python extending/
embedding manual*/
# include "Python.h"
static PyObject *SpamError;
static PyObject *spam_system(self, args)
    PyObject *self;
    PyObject *args;
{
    char *command;
    int sts;
    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = system(command);
    return Py_BuildValue("i", sts);
}
static PyMethodDef SpamMethods[] = {
    {"system",  spam_system, METH_VARARGS},
    {NULL,      NULL}        /* Sentinel */
};
#ifdef MS_WIN32
__declspec(dllexport)
#endif
void initspam()
{
    PyObject *m, *d;
    m = Py_InitModule("spam", SpamMethods);
    d = PyModule_GetDict(m);
    SpamError = PyErr_NewException("spam.error", NULL, NULL);
    PyDict_SetItemString(d, "error", SpamError);
}

构建该扩展有两种方法:

2.4.1 使用 compile.py 工具
  • 创建一个包含 spammodule.c 和 setup.in 文件的目录,setup.in 文件内容如下:
*shared*
spam spammodule.c
  • 从该目录运行 compile.py 工具,它会生成 Visual C++ 项目和工作区文件,并完成项目构建。
  • 将最终的 spam.pyd 复制到 PythonPath 上的目录,如 C:\Program Files\Python\Dlls。
2.4.2 手动使用 Visual C++

手动使用 Visual C++ 构建项目的步骤如下:
1. 创建新项目文件
1. 启动 Microsoft Visual C++。
2. 选择 File -> New -> Projects -> Win32 Dynamic Link Library。
3. 在 Location 下选择一个目录。
4. 在 Project Name 框中输入 spam。
5. 选择 OK 启动新项目向导,选择“An empty DLL Project”。
6. 确认后,VC++ 创建一个空项目。
7. 将 spammodule.c 源文件放入新的 spam 目录。
8. 定位并选择 Workspace Explorer 窗口底部的 File View 选项卡。
9. 右键单击 Spam Files,选择 Add Files To Project,选择 spammodule.c 源文件。
10. 展开 Source Files 树并双击 spammodule.c,在 Visual C++ 中打开。
2. 修改项目设置
1. 选择 Project -> Settings,在左上角组合框中选择 Win32 Release 配置。
2. 选择 C/C++ 选项卡,下拉 Category 组合框,选择 Code Generation,将“Use runtime library”更改为“Multithreaded DLL”。
3. 选择 Link 选项卡,将输出文件的名称从 Release/spam.dll 更改为 Release/spam.pyd。
4. 若需要进行调试构建,对 Win32 Debug 配置重复上述过程,但将第一步中的“Multithreaded DLL”替换为“Debug Multithreaded DLL”,并将输出文件更改为 spam_d.pyd。
3. 构建项目
1. 选择 Build -> Set Active Configuration,选择 Win32 Release。
2. 选择 Build -> Build spam.pyd。

2.5 调试与发布构建

调试和发布构建的区别主要在于 C 运行时库的使用:
- 发布构建必须使用 Multithreaded DLL 并链接标准 Python .lib 文件。
- 调试构建必须使用 Debug Multithreaded DLL C 运行时库,链接 _d 版本的 Python .lib 文件,并遵循 _d 命名约定。

2.6 构建 Python 本身

有时需要从源代码构建 Python 本身,如构建调试版本或获得从源代码构建整个项目的满足感和安全感。构建过程很简单,Python 源代码带有 Visual C++ 项目和工作区文件,只需打开工作区并开始构建即可。

2.7 在 C++ 应用程序中嵌入 Python 解释器

将 Python 嵌入到另一个现有应用程序中,称为嵌入 Python。Python 本身的大部分功能由 Python15.dll 实现,Python.exe 只是简单地使用该 DLL。要开始嵌入 Python,可阅读扩展和嵌入文档,并参考 Python 源代码的 Demo\Embed 目录中的示例,然后查阅 Python/C API 文档。

2.8 简化包装器和接口生成器(SWIG)

SWIG 是一个由 David Beazley 编写的工具,可帮助将 Python、Perl 和 Tcl/Tk 等高级语言编写的程序与低级 C 和 C++ 代码连接起来。许多流行的 Python 扩展都是使用 SWIG 构建的,在进行任何非平凡的 Python 扩展项目之前,应考虑使用 SWIG。

3. Python 与 Delphi

3.1 Delphi 概述

Delphi 是一种流行的编程语言,结合了 Visual Basic 的易用性和 C++ 的强大功能,其可视化组件库能很好地隐藏 Windows API 的复杂性。Delphi 使用 Object Pascal 语言,支持 C 调用约定,理论上可以像 C/C++ 程序一样访问 Python 主 DLL,并编译 Python 可用的 DLL 扩展。

3.2 PyDelphi 包

PyDelphi 包使 Python 和 Delphi 在 C 级别上的集成几乎毫不费力。它包含一个可以安装在组件库中的 Delphi 包库,以及一套全面的演示和教程。核心组件是一个名为 PythonEngine.pas 的 Pascal 模块,它声明了与 Python.h 中匹配的 Pascal 类型和与 Python DLL 导出的大多数函数头匹配的函数。

3.3 在 Delphi 应用程序中嵌入 Python

以下是在 Delphi 应用程序中嵌入 Python 的步骤:
1. 创建一个包含特定可视化组件的新项目。
2. 在窗体上放置两个特殊的 Python - Delphi 组件:PythonEngine 和 PythonGUIInputOutput。
3. 设置 PythonEngine 的 InitScript 属性,该属性可以在设计时设置为包含任何 Python 代码的字符串列表。
4. 设置 PythonGUIInputOutput 的属性,将 Python 引擎的输出重定向到窗体上的 Rich Edit 窗口。
5. 在按钮的点击事件中添加以下代码:

procedure TForml.Button1Click(Sender: TObject);
begin
  PythonEngine1.ExecStrings( Memo1.Lines );
end;

3.4 使用 Delphi DLL 扩展 Python

可以在 Delphi 中创建一个 DLL 并将其作为 Python 模块暴露出来。以下是一个示例代码:

unit module;
interface
uses PythonEngine;
procedure initdemodll; cdecl;
var
  gEngine : TPythonEngine;
  gModule : TPythonModule;
implementation
function Add( Self, Args : PPyObject ) : PPyObject; far; cdecl;
var
  a, b : Integer;
begin
  with GetPythonEngine do
    begin
      if PyArg_ParseTuple( args, 'ii:Add', [@a, @b] ) <> 0 then
        begin
          Result := PyInt_FromLong(a + b);
        end
      else
        Result := nil;
    end;
end;
procedure initdemodll;
begin
  try
    gEngine := TPythonEngine.Create(nil);
    gEngine.AutoFinalize := False;
    gEngine.LoadDll;
    gModule := TPythonModule.Create(nil);
    gModule.Engine := gEngine;
    gModule.ModuleName := 'demodll';
    gModule.AddMethod( 'add', @Add, 'add(a,b) -> a+b' );
    gModule.Initialize;
  except
  end;
end;
initialization
finalization
  gEngine.Free;
  gModule.Free;
  frmAbout.Free;
end.

编辑 Delphi 项目文件(扩展名为 DPR)以导出 initdemodll 函数:

library DemoDll;
uses
  SysUtils,
  Classes,
  module in 'module.pas';
exports
  initdemodll;
{$E pyd}
begin
end.

将项目编译为 DLL 并保存为 .PYD 文件,放置在 PythonPath 上的某个目录中。

3.5 访问 Delphi 的可视化组件库

可以在 Delphi 中编写 GUI 代码,并通过 Python 调用。但在 PythonWin 编辑器中运行使用 GUI 的 DLL 时会出现问题,因为 Delphi VCL 应用程序框架和 PythonWin 中的 MFC 应用程序框架会冲突。不过,PyDelphi 的作者已经编写了自己的 Python IDE 和一个自动检查 Pascal 源代码并为整个可视化组件库生成 Python 包装器的工具,目前该功能仍处于实验阶段,仅限于在 Delphi 应用程序中使用。

3.6 动态 DLL 访问

Sam Rushing 编写的扩展允许 Python 动态加载和调用任何 DLL 中的任何函数。CallDLL 包包含一个 Python 扩展模块 calldll.pyd,提供了加载模块和调用函数的低级 API;DynWin 包在此基础上提供了更高级的 API。使用这些工具时,需要确保传递的参数类型正确,否则可能会导致栈损坏或程序崩溃。

3.7 安装和设置

从 Sam Rushing 的网站下载 CallDLL 和 DynWin 包,将 calldll.pyd 和 windll.py 安装到 PythonPath 上。

3.8 使用 WinDll

以下是一个使用 WinDll 加载和使用简单 DLL 的示例:

>>> from dynwin.windll import *
>>> mod1 = module('c:\\temp\\simple') # loads the DLL
>>> mod1.handle         # it can report its location in memory
22806528
>>> mod1.Min(27, 28)    # loads and executes Min function
27
>>> mod1.Min            # we now have a 'callable function' object…
<callable function "Min">
>>> mod1.Min.address    #…which knows its address too
22836704

WinDLL 可以透明地处理任何整数或指针参数,若需要处理其他类型的参数,可能需要使用 CallDLL 中的低级参数格式化函数。WinDLL 还包含一个 cstring 类,可方便地传递字符串或字符缓冲区参数。

综上所述,通过 Visual C++ 和 Delphi 可以有效地扩展和嵌入 Python,为 Python 应用程序带来更多的功能和灵活性。不同的方法适用于不同的场景,开发者可以根据具体需求选择合适的方式。在实际应用中,需要注意调试和发布构建的区别,以及动态 DLL 访问的风险。

4. 总结与技巧回顾

4.1 关键技术点总结

技术点 描述
Visual C++ 构建 Python 扩展 可手动编写或使用 compile.py 工具,需注意 C 运行时库和输出文件扩展名的设置
Delphi 集成 Python 通过 PyDelphi 包实现,能在 Delphi 应用中嵌入 Python 或用 Delphi DLL 扩展 Python
SWIG 帮助连接高级语言与 C/C++ 代码,用于构建 Python 扩展
动态 DLL 访问 利用 CallDLL 和 DynWin 包,可动态加载和调用 DLL 函数

4.2 操作技巧回顾

  • Visual C++ 配置 :全局指定 Python 目录,避免在项目文件中硬编码,方便升级 Python。
  • 调试与发布构建 :发布用 Multithreaded DLL 链接标准 .lib 文件,调试用 Debug Multithreaded DLL 链接 _d 版本 .lib 文件并遵循 _d 命名约定。
  • 动态 DLL 访问 :确保传递参数类型正确,使用 cstring 类处理字符串参数。

4.3 流程图:Visual C++ 构建 Python 扩展流程

graph LR
    A[确定 Python 文件位置] --> B[启动 Visual C++]
    B --> C[设置 Include Files 目录]
    C --> D[设置 Library files 目录]
    D --> E[选择 OK 关闭对话框]
    E --> F{选择构建方式}
    F -->|compile.py 工具| G[创建包含文件的目录]
    F -->|手动构建| H[创建新项目文件]
    G --> I[运行 compile.py 工具]
    I --> J[复制 spam.pyd 到 PythonPath]
    H --> K[修改项目设置]
    K --> L[构建项目]
    L --> M[复制 spam.pyd 到 PythonPath]

5. 常见问题与解决方案

5.1 Visual C++ 构建问题

  • 找不到 Python 文件 :检查是否正确设置了 Include Files 和 Library files 目录,可使用全局设置避免该问题。
  • C 运行时库不匹配 :确保发布和调试构建使用正确的 C 运行时库,遵循相应的命名约定。

5.2 Delphi 集成问题

  • GUI 冲突 :避免在 PythonWin 编辑器中运行使用 GUI 的 Delphi DLL,可在 Delphi 应用中正常使用。
  • PyDelphi 组件初始化失败 :检查 PythonEngine 和相关组件的属性设置,确保正确加载 Python DLL。

5.3 动态 DLL 访问问题

  • 参数类型错误 :仔细检查传递给 DLL 函数的参数类型,使用 CallDLL 的低级参数格式化函数处理复杂类型。
  • 栈损坏或崩溃 :确保参数类型和数量正确,避免传递无效参数。

5.4 解决方案列表

问题 解决方案
找不到 Python 文件 检查并正确设置 Visual C++ 的 Include 和 Library 目录
C 运行时库不匹配 按要求设置发布和调试构建的 C 运行时库及命名约定
GUI 冲突 不在 PythonWin 中运行使用 GUI 的 Delphi DLL
PyDelphi 组件初始化失败 检查 PythonEngine 等组件属性设置
参数类型错误 使用 CallDLL 低级函数处理参数
栈损坏或崩溃 确保传递参数的正确性

6. 实际应用案例分析

6.1 数据处理应用

在一个数据处理项目中,需要对大量复杂数据集进行处理。使用 Python 进行数据的读取和初步处理,但对于计算密集型的部分,使用 C 语言编写扩展模块,通过 Visual C++ 构建为 Python 可调用的扩展。这样既利用了 Python 的简洁性和丰富的库,又通过 C 语言提高了计算性能。

6.2 自动化测试应用

在自动化测试场景中,使用 Delphi 开发测试框架,嵌入 Python 解释器作为脚本语言。测试人员可以编写 Python 脚本来定义测试用例和流程,通过 Delphi 的可视化界面进行管理和执行。这种方式结合了 Delphi 的开发效率和 Python 的灵活性。

6.3 跨平台应用

对于需要跨平台的应用,使用 SWIG 生成 Python 扩展,将 C/C++ 代码与 Python 集成。这样可以在不同的操作系统上使用相同的 Python 代码调用底层的 C/C++ 功能,提高了代码的可移植性。

6.4 案例对比表格

应用场景 技术选择 优势
数据处理 Visual C++ 构建 C 扩展 提高计算性能
自动化测试 Delphi 嵌入 Python 结合开发效率和灵活性
跨平台应用 SWIG 生成扩展 提高代码可移植性

7. 未来发展趋势

7.1 技术融合趋势

未来,Python 与 Visual C++、Delphi 等语言的融合将更加紧密。随着技术的发展,可能会出现更便捷的工具和框架,进一步简化扩展和嵌入的过程,降低开发门槛。

7.2 性能优化趋势

对于计算密集型应用,会有更多的优化技术出现,如利用多核处理器、GPU 加速等,提高 Python 扩展的性能。

7.3 应用领域拓展趋势

Python 扩展和嵌入技术将在更多领域得到应用,如人工智能、物联网、大数据等,为这些领域的开发提供更强大的支持。

7.4 趋势流程图

graph LR
    A[技术融合] --> B[更便捷工具框架]
    C[性能优化] --> D[多核、GPU 加速]
    E[应用领域拓展] --> F[人工智能、物联网、大数据]
    B --> G[简化开发过程]
    D --> H[提高扩展性能]
    F --> I[支持多领域开发]

通过以上对 Python 与 Visual C++、Delphi 结合的扩展和嵌入技术的介绍,我们可以看到这些技术为开发者提供了丰富的选择和强大的功能。在实际开发中,开发者应根据具体需求选择合适的技术和方法,同时关注未来的发展趋势,不断提升自己的开发能力。

【最优潮流】直流最优潮流(OPF)课设(Matlab代码实现)内容概要:本文档主要围绕“直流最优潮流(OPF)课设”的Matlab代码实现展开,属于电力系统优化领域的教学科研实践内容。文档介绍了通过Matlab进行电力系统最优潮流计算的基本原理编程实现方法,重点聚焦于直流最优潮流模型的构建求解过程,适用于课程设计或科研入门实践。文中提及使用YALMIP等优化工具包进行建模,并提供了相关资源下载链接,便于读者复现学习。此外,文档还列举了大量电力系统、智能优化算法、机器学习、路径规划等相关的Matlab仿真案例,体现出其服务于科研仿真辅导的综合性平台性质。; 适合人群:电气工程、自动化、电力系统及相关专业的本科生、研究生,以及从事电力系统优化、智能算法应用研究的科研人员。; 使用场景及目标:①掌握直流最优潮流的基本原理Matlab实现方法;②完成课程设计或科研项目中的电力系统优化任务;③借助提供的丰富案例资源,拓展在智能优化、状态估计、微电网调度等方向的研究思路技术手段。; 阅读建议:建议读者结合文档中提供的网盘资源,下载完整代码工具包,边学习理论边动手实践。重点关注YALMIP工具的使用方法,并通过复现文中提到的多个案例,加深对电力系统优化问题建模求解的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值