Python作为一门高级编程语言,以其简洁的语法和丰富的库生态赢得了开发者的青睐。然而,在计算密集型任务中,Python的性能往往无法满足要求。Python调用C/C++函数库成为提升应用性能的关键技术路径,通过将底层计算逻辑用C/C++实现,再通过适当的接口与Python交互,可以在保持开发效率的同时获得接近系统语言的执行性能。本文将深入探讨Python调用C/C++函数库的多种方法,包括它们的工作原理、实现步骤、优缺点及适用场景,帮助开发者根据具体需求选择最适合的集成方案。

一、主流调用方法及其基本原理

Python调用C/C++函数库主要有五种主流方法,各有其独特的实现机制和适用范围:

ctypes是Python标准库的一部分,提供了一种直接与C语言兼容的数据类型和函数调用方式。它通过动态加载共享库(.so或.dll)并在内存中创建对应的函数指针来实现调用,无需任何预编译步骤。ctypes的工作原理类似于Windows平台上的DLL调用或Linux平台上的动态链接库加载,通过函数指针和参数类型转换直接调用C函数。

SWIG(SimplifiedWrapper and Interface Generator)是一个开源的软件接口生成器,能够自动生成C/C++与Python之间的接口代码。SWIG通过解析C/C++头文件和接口描述文件(.i),生成特定语言的包装代码,这些代码负责在Python和C/C++之间进行参数转换和内存管理。SWIG支持多种语言和复杂的C++特性,如类、继承、模板等,是处理大型C++项目时的常用工具。

cffi(C Foreign Function Interface)是另一个Python库,用于调用C语言函数。与ctypes不同,cffi采用声明式接口,开发者可以使用接近C语法的声明来定义函数和数据结构。cffi的优势在于其可读性和维护性,同时它还支持与PyPy解释器的兼容,这在某些高性能场景中非常有价值。

Python/C API是Python官方提供的扩展接口,允许开发者用C/C++编写Python模块。这种方法需要开发者深入理解Python对象模型和内存管理机制,通过一系列宏和函数(如PyMOD初始化、PyMethodDef定义等)手动创建Python可调用的对象和方法。Python/C API提供了最大的灵活性,但开发复杂度也最高。

pybind11是一个现代的C++库,旨在简化C++与Python之间的绑定过程。它通过C++模板和编译时类型推导,将C++代码无缝暴露给Python,无需手动编写大量包装代码。pybind11支持C++11及更高版本的特性,如智能指针、移动语义等,是当前推荐的C++与Python集成方案。

二、实现步骤与代码示例

1. ctypes方法

ctypes是最简单的调用方式,适合快速原型开发和简单函数调用。实现步骤如下:

编写C/C++函数并导出为共享库

// add.c
#include <stdio.h>int add_int(int a, int b) {printf("Adding %d and %d\n", a, b);return a + b;
}float add_float(float a, float b) {printf("Adding %f and %f\n", a, b);return a + b;
}

编译为共享库:

gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c

Python调用代码

import ctypes# 加载共享库
adder = ctypes.CDLL('./adder.so')# 设置函数参数类型和返回值类型
adder.add_int.argtypes = [ctypes.c_int, ctypes.c_int]
adder.add_int.restype = ctypes.c_intadder.add_float.argtypes = [ctypes.c_float, ctypes.c_float]
adder.add_float支柱 = ctypes.c_float# 调用函数
result_int = adder.add_int(4, 5)
print(f"4 + 5 = {result_int}")a = ctypes.c_float(5.5)
b = ctypes.c_float(4.1)
result_float = adder.add_float(a, b)
print(f"5.5 + 4.1 = {result_float}")

C++类调用:由于C++支持函数重载,编译器会修改函数名,ctypes无法直接调用。解决方法是在C++代码中使用extern “C”声明:

// TestLib.cpp
#include <iostream>extern "C" {class TestLib {public:void display() {std::cout << "First display" << std::endl;}void display(int a) {std::cout << "Second display:" << a << std::endl;}};TestLib global_obj;void display() {global_obj.display();}void display_int(int a) {global_obj.display(a);}
}

编译命令:

g++ -shared -fPIC TestLib.cpp -o libTestLib.so

Python调用:

import ctypeslib = ctypes.CDLL('./libTestLib.so')lib.display()
lib.display_int(100)
2. cffi方法

cffi提供了更接近C语法的接口定义,适合需要在Python中嵌入C代码的场景。实现步骤如下:

编写C/C++函数并导出为共享库

// ffi_test.cpp
extern "C" {int add(int a, int b) {return a + b;}
}

编译命令:

g++ffi_test.cpp -fPIC -shared -o libffi_test.so

Python调用代码

from cffi import FFIffi = FFI()
# 声明C函数接口
ffi.cdef("""int add(int a, int b);"""
)# 加载共享库
lib = ffi.dlopen('libffi_test.so')# 调用函数
print(f"3 + 4 = {lib.add(3, 4)}")

Python代码中嵌入C代码(无需编译为共享库):

from cffi import FFIffi = FFI()
# 声明C函数接口
ffi.cdef("""int add(int a, int b);"""
)# 定义并编译C代码
lib =ffi.verify("""int add(int a, int b) {return a + b;}"""
)print(f"3 + 4 = {lib.add(3, 4)}")
3. SWIG方法

SWIG适合处理复杂的C++项目,能够自动处理类、继承、模板等特性。实现步骤如下:

编写C++类和接口文件

// TestLib.h
#include <iostream>class TestLib {
public:TestLib();~TestLib();void display();void display(int a);int add(int a, int b);float add(float a, float b);
};// TestLib.cpp
#include "TestLib.h"TestLib::TestLib() {std::cout << "TestLib created" << std::endl;
}TestLib::~TestLib() {std::cout << "TestLib destroyed" << std::endl;
}void TestLib::display() {std::cout << "First display" << std::endl;
}void TestLib::display(int a) {std::cout << "Second display:" << a << std::endl;
}int TestLib::add(int a, int b) {return a + b;
}float TestLib::add(float a, float b) {return a + b;
}// TestLib.i
%module TestLib%{
#include "TestLib.h"
%}// 声明C++类
class TestLib {
public:TestLib();~TestLib();void display();void display(int a);int add(int a, int b);float add(float a, float b);
};

编译SWIG接口

swig -c++ -python TestLib.i
g++ -fPIC -c TestLib.cpp
g++ -fPIC -c TestLib wrap.cpp
g++ -shared TestLib.o TestLib wrap.o -o _TestLib.so

Python调用代码

import TestLib# 创建C++对象
obj = TestLib.TestLib()# 调用成员函数
obj.display()
obj.display(100)# 调用重载函数
print(f"5 + 3 = {obj.add(5, 3)}")
print(f"2.5 + 3.1 = {obj.add(2.5, 3.1)}")
4. Python/C API方法

Python/C API提供了最大的灵活性,但开发复杂度也最高。实现步骤如下:

编写C++扩展模块

// module.cpp
#include <Python.h>
#include <iostream>// C++类
class TestLib {
public:void display() {std::cout << "First display" << std::endl;}void display(int a) {std::cout << "Second display:" << a << std::endl;}int add(int a, int b) {return a + b;}float add(float a, float b) {return a + b;}
};// Python类型定义
static PyTypeObject TestLibType = {PyVarObjectHead_init"TestLib",sizeof(TestLib),0,// 方法表.tpMethods = methods,
};// 方法定义
static PyMethodDef methods[] = {{"display", (PyCFunction)display, METH_VARARGS, "Display message"},{"display_int", (PyCFunction)display_int, METH_VARARGS, "Display integer"},{"add", (PyCFunction)add, METH_VARARGS, "Add two numbers"},{NULL, NULL, 0, NULL}
};// 模块初始化函数
static struct PyModuleDef moduledef = {PyModuleDefHead_init"module",NULL,0,.mMethods = NULL,.mModuleInit = PyMODInit_module
};PyMODInit_t PyMODInit_module() {// 初始化Python解释器Py_Initialize();// 创建模块PythonModule* module = PyModuleDefInit(&moduledef);// 创建类型if (PyType_Ready(&TestLibType) < 0)return NULL;// 将类型添加到模块PyModuleDictSetItemStr(module-> ob_type, "TestLib", (PyObject*) &TestLibType);return module;
}

编写setup.py

from setuptools import setup, Extensionmodule = Extension('module',sources=['module.cpp'])setup(name='module',version='1.0',description='Python C++ extension',ext_modules=[module])

编译扩展模块

python setup.py build_ext --inplace

Python调用代码

import module# 创建C++对象
obj = module.TestLib()# 调用成员函数
obj.display()
obj.display_int(100)# 调用函数
print(f"5 + 3 = {obj.add(5, 3)}")
print(f"2.5 + 3.1 = {obj.add(2.5, 3.1)}")
5. pybind11方法

pybind11是目前推荐的现代C++与Python集成方案,实现步骤如下:

编写C++代码和绑定

// example.cpp
#include <pybind11/pybind11.h>using namespace pybind11;class TestLib {
public:void display() {std::cout << "First display" << std::endl;}void display(int a) {std::cout << "Second display:" << a << std::endl;}int add(int a, int b) {return a + b;}float add(float a, float b) {return a + b;}
};PYBIND11_MODULE(example, m) {// 绑定C++类到Pythonm.def("add_int", &TestLib::add, "Add two integers");m.def("add_float", &TestLib::add, "Add two floats");// 绑定类到Pythonpy::class_<TestLib>(m, "TestLib").def py::init<>()).def("display", &TestLib::display).def("display_int", &TestLib::display_int);
}

编译扩展模块

c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)

Python调用代码

import example# 创建C++对象
obj = example.TestLib()# 调用成员函数
obj.display()
obj.display_int(100)# 调用函数
print(f"5 + 3 = {example.add_int(5, 3)}")
print(f"2.5 + 3.1 = {example.add_float(2.5, 3.1)}")

三、不同方法的优缺点与适用场景

下表对五种主流方法进行了系统性比较:

方法

开发复杂度

性能

语言支持

维护性

适用场景

ctypes

C函数

快速原型开发、简单函数调用

cffi

C函数

需要PyPy兼容、轻量级C调用

SWIG

中高

C++类、继承、模板

大型C++项目、复杂接口

Python/C API

最高

C++类、继承、模板

需要深度定制、高性能需求

pybind11

C++11及以上

现代C++项目、简洁接口

ctypes的优势在于简单易用,无需额外编译步骤,适合快速验证C函数调用。但其缺点也很明显:不支持C++类和重载,需要手动处理参数类型和内存管理,难以处理复杂数据结构。

cffi相比ctypes提供了更好的可读性和维护性,支持更接近C语法的声明方式,同时兼容PyPy解释器。这对于需要在不同Python实现上运行的程序非常有价值。然而,cffi同样不支持C++类和重载,需要通过C接口间接调用C++功能。

SWIG是处理复杂C++项目的强大工具,能够自动生成Python绑定代码,支持类、继承、模板等高级特性。SWIG的灵活性使其成为许多大型项目的首选。然而,SWIG的学习曲线较陡,需要编写接口描述文件,并且对于某些C++语法(如非常规类型声明)的支持有限。

Python/C API提供了最大的灵活性和控制权,允许开发者完全定制Python与C/C++之间的交互。这对于需要深度集成或特殊性能优化的场景非常有价值。然而,Python/C API的开发复杂度最高,需要深入理解Python对象模型和内存管理机制,维护成本也相应较高。

pybind11是目前推荐的现代C++与Python集成方案,它结合了SWIG的灵活性和Python/C API的性能优势,同时简化了开发流程。pybind11支持C++11及以上版本的特性,如智能指针、移动语义等,使得C++代码可以保持现代风格。此外,pybind11还提供了丰富的文档和示例,降低了学习曲线。然而,pybind11需要C++11及以上版本的编译器支持,这对于某些遗留系统可能构成限制。

四、性能比较与选择建议

在实际应用中,性能是选择调用方法的重要考量因素。根据多个测试案例,不同方法的性能表现如下:

ctypes的调用开销约为纯C函数的1.5-2倍,适合简单的函数调用和快速原型开发。对于需要频繁调用的函数,ctypes的性能可能无法满足要求。

cffi在性能上与ctypes相当,但在代码可读性和维护性方面有所优势。此外,cffi在PyPy解释器上的表现通常优于ctypes,这对于需要高性能且与PyPy兼容的场景非常有价值。

SWIG生成的绑定代码在性能上接近原生C/C++调用,但需要额外的编译步骤。对于复杂的C++项目,SWIG的性能开销通常可以忽略不计。

Python/C API提供了最高的性能,几乎与纯C/C++调用相当,适合对性能要求极高的场景。然而,其开发复杂度也最高,需要开发者深入理解Python内部机制。

pybind11在性能上与Python/C API相当,但开发复杂度显著降低。这对于大多数现代C++项目来说是一个理想的选择,可以在保持高性能的同时减少开发和维护成本。

基于上述分析,以下是针对不同场景的调用方法选择建议:

对于简单函数调用和快速原型开发,ctypes是最佳选择,其简单易用的特性可以快速验证C函数调用。

对于需要PyPy兼容或轻量级C调用的场景,cffi是一个更好的选择,它提供了更好的可读性和维护性。

对于大型C++项目或复杂接口,SWIG是首选工具,它能够自动生成Python绑定代码,支持类、继承、模板等高级特性。

对于需要深度定制或特殊性能优化的场景,Python/C API提供了最大的灵活性,但需要开发者具备深入的Python和C/C++知识。

对于现代C++项目,pybind11是当前推荐的方案,它结合了SWIG的灵活性和Python/C API的性能优势,同时简化了开发流程,支持C++11及以上版本的特性。

五、实际应用案例与最佳实践

科学计算与数据分析:在RPLIDAR数据通讯和解析项目中,使用C++编写数据解析模块,将运算结果写入共享内存块,再通过Python进行数据处理和可视化。这种方法将C++的高性能与Python的易用性相结合,显著提升了程序的执行效率。

机器学习与深度学习:在CGAL(计算几何算法库)的Python绑定中,使用SWIG自动生成Python接口,同时保留C++的模板特性和高性能。这种方法使得复杂的几何计算可以在Python环境中高效执行,同时保持代码的可维护性和扩展性。

Web开发与系统集成:在Flask框架下集成模拟机接口(如RINSIM平台的Dataport.dll),使用pybind11对C++函数进行封装,生成Python模块。这种方法使得复杂的工业控制逻辑可以在Python Web应用中高效调用,同时保持代码的简洁性和可读性。

最佳实践

  1. 明确需求:在选择调用方法之前,明确项目的具体需求,包括性能要求、复杂度、维护周期等。
  2. 简化接口:无论使用哪种方法,都应尽量简化C/C++与Python之间的接口,减少跨语言调用的开销。
  3. 处理内存管理:跨语言调用需要特别注意内存管理,避免内存泄漏或无效指针访问。
  4. 利用现代C++特性:在使用pybind11等现代工具时,充分利用C++11及以上版本的特性,如智能指针、移动语义等,简化代码并提高安全性。
  5. 测试与验证:在实际应用中,充分测试跨语言调用的性能和稳定性,确保接口的正确性和可靠性。

六、未来发展趋势与技术展望

随着Python和C++生态的不断发展,Python调用C/C++函数库的技术也在持续演进:

类型系统增强:现代工具如pybind11和SWIG正在不断改进对C++类型系统的支持,使得C++的复杂数据结构可以在Python中更自然地表示和操作。

编译器支持改进:C++编译器(如GCC、Clang)对Python绑定的支持也在不断提升,使得C++代码与Python的集成更加无缝。

多解释器兼容:随着PyPy等替代Python解释器的普及,cffi等工具对多解释器的兼容性变得越来越重要,未来可能会有更多工具支持这一特性。

自动化绑定生成:随着AI技术的发展,可能会出现更智能的绑定生成工具,能够自动分析C/C++代码并生成Python接口,进一步降低开发复杂度。

跨平台支持:Python应用通常需要跨平台运行,未来工具可能会更好地支持Windows、Linux、macOS等不同平台的C/C++库调用。

性能优化:随着计算需求的不断提升,工具可能会提供更精细的性能优化选项,如缓存机制、并行计算支持等。

结论:Python调用C/C++函数库是提升应用性能的重要技术路径。根据项目需求、开发复杂度、性能要求和维护周期等因素,可以选择合适的调用方法。对于大多数现代C++项目,pybind11是当前推荐的方案,它结合了SWIG的灵活性和Python/C API的性能优势,同时简化了开发流程。而对于简单的函数调用和快速原型开发,ctypes或cffi可能是更好的选择。无论选择哪种方法,都应遵循最佳实践,确保接口的正确性和可靠性,同时充分利用现代C++和Python特性,提升代码质量和性能。

参考来源:

1. 【py-22】python调用C/C++的几种方法

2. Python调用C/C++-阿里云开发者社区

3. 简单的Python调用C++程序-腾讯云开发者社区-腾讯云

4. Python调用C/C++代码-CSDN博客

5. Python怎么实现调用c/cpp的库?

6. 简单的Python调用C/C++程序的方法_python 调用c++-CSDN博客

7. Linux平台Python调用C/C++代码四种方法案例解析-CSDN文库

8. python3调用c++动态库(linux)

9. Python使用Ctypes调用C/C++动态库_python调用c++库-CSDN博客

10. python调用C++库-CSDN博客

11. DeePMD-kit v2: A software package for Deep Potential models

12. SWIG教程《二》知乎

13. C++和python的代码如何相互调用?

14. swig支持WebAssembly的embind绑定

15. python cffi如何调试?知乎

16. SWIG教程《二》知乎

17. Python 通过FFI调用C/C++代码

18. 为Python编写C++扩展-Visual Studio(Windows)Microsoft Learn

19. swig支持WebAssembly的embind绑定

20. Linux平台Python调用C/C++代码四种方法案例解析-CSDN文库

21. SWIG教程《二》知乎

22. python调用C++的方法各有什么优势,哪个最好?知乎

23. 为Python编写C++扩展-Visual Studio(Windows)Microsoft Learn

24. swig支持WebAssembly的embind绑定

25. Python 通过FFI调用C/C++代码

26. Reticula: A temporal network and hypergraph analysis software package

27. A New Parallel Algorithm for Sinkhorn Word-Movers Distance and Its Performance on PIUMA and Xeon CPU

28. 深度解析C++与Python的交互机制-编程语言-亿速云

29. CGAL Made More Accessible

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92981.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92981.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/92981.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【21】OpenCV C++实战篇——OpenCV C++案例实战二十七《角度测量》

OpenCV C案例实战二十七《角度测量》 利用opencv获取三点所形成直线的角度

程序在计算机中的运行方式

程序在计算机中的运行是一个涉及硬件、操作系统和软件协同工作的复杂过程。我们可以将其分解为几个关键阶段来理解&#xff1a;1. 程序的诞生&#xff1a;从源代码到可执行文件 编写代码&#xff1a;程序员使用高级编程语言&#xff08;如C、Python、Java&#xff09;编写源代码…

虚拟卡券管理平台详细设计文档

文章目录**1. 文档概述**1.1 目标1.2 核心能力**2. 业务场景分析**2.1 用户场景2.2 关键业务流程卡券核销流程&#xff1a;**3. 整体架构设计**3.1 技术栈3.2 微服务拆分**4. 功能模块详细设计**▶ 4.1 卡券生命周期管理**4.1.1 卡券类型设计****4.1.2 关键状态机**▶ 4.2 卡券…

Oracle参数Process

RDBMS&#xff1a; 19.28 参考文档&#xff1a; IF:How to determine an optimum value for PROCESSES parameter (Doc ID 2012693.1) All About the Initialization Parameter PROCESSES and the Related Issues (Doc ID 2673195.1) How to calculate the proper value from …

【数据结构入门】树

目录 1.树的概念 父子结点 根节点|叶节点 结点的度 叶子结点或终端结点 兄弟结点 树的度 结点的层次 树的高度或深度 结点的祖先 堂兄弟结点 子孙 森林 2. 树的结构定义 2.1 左孩子右兄弟结构 2.2 数组表示法 3.树&非树 1.树的概念 树是一种非线性的数据结…

手把手教你用 Flink + CDC 实现 MySQL 数据实时导入 StarRocks(干货)

手把手教你用 Flink CDC 实现 MySQL 数据实时导入 StarRocks&#xff08;干货&#xff09; 如何利用 Apache Flink 结合 CDC&#xff08;Change Data Capture&#xff0c;变更数据捕获&#xff09;技术&#xff0c;将 MySQL 的数据实时导入 StarRocks&#xff0c;打造高效的实…

Rust:anyhow 高效错误处理库核心用法详解

以下是 anyhow 库在 Rust 中的核心用法详解&#xff08;结合最佳实践和示例&#xff09;&#xff1a; &#x1f530; 一、anyhow 的核心价值 用于简化错误处理&#xff0c;尤其适合&#xff1a; 需要快速原型开发的应用需要丰富错误上下文&#xff08;Context&#xff09;的场…

阿里云服务linux安装单机版

一、单机安装Redis 阿里教程 下载地址:redis下载地址 1、首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tcl 2、下载Redis 注&#xff1a;也可以自己下好然后上传到云服务 wget https://gitcode.net/weixin_44624117/software/-/raw/master/software/Li…

python之uv使用

文章目录安装与更新standalonepip 安装创建以及初始化项目依赖管理uv run直接在命令行运行python代码片段直接运行项目中可执行脚本文件运行python包中快捷指令uv项目本地运行调试细节vscode 中运行调试uv项目命令行运行深入理解 uv lock, uv sync, uv lockuv lock 行为解析:uv…

【CV 目标检测】①——目标检测概述

一、目标检测概述 1.目标检测 目标检测&#xff08;Object Detection&#xff09;的任务是找出图像中所有感兴趣的目标&#xff0c;并确定它们的类别&#xff08;分类任务&#xff09;和位置&#xff08;回归任务&#xff09; 目标检测中能检测出来的物体取决于当前任务&…

C#图形库SciChart与ScottPlot及LiveCharts2对比

一.概述 1.SciChart SciChart 是一个专为企业级应用设计的高性能数据可视化库&#xff0c;提供跨平台的图表解决方案&#xff0c;支持 .NET、JavaScript、iOS 和 Android 等多个平台。它以卓越的渲染性能、丰富的专业图表类型和强大的交互功能著称&#xff0c; 广泛应用于金…

Win10电脑密码忘记如何进入操作系统

http://xq128.com/zj.htmlhttps://share.feijipan.com/s/LbFdbUKl下载后&#xff0c;准备一个空的U盘&#xff0c;大于4G。将U盘制作为PE盘。之后将制作好的PE盘插入到电脑中&#xff0c;启动待去除密码的电脑台式机&#xff0c;启动后一直按住F12&#xff0c;进入BIOS。选择下…

[免费]基于Python的网易云音乐热门歌单可视化大屏项目(flask+pandas+echarts+request库)【论文+源码+SQL脚本】

大家好&#xff0c;我是python222_小锋老师&#xff0c;看到一个不错的基于Python的网易云音乐热门歌单可视化大屏项目(flaskpandasechartsrequest库)&#xff0c;分享下哈。 项目视频演示 【免费】基于Python的网易云音乐热门歌单可视化大屏项目(flaskpandasecharts爬虫) Py…

AR 智能眼镜:从入门到未来

从零看懂 AR 智能眼镜:未来 10 年技术演进与新手入门指南 在这个数字技术飞速迭代的时代,AR 智能眼镜正从科幻电影走进现实。从 2025 年重量不足 35 克的消费级产品,到 2030 年成为 “第二大脑” 的生活刚需,再到 2040 年进化为神经接口终端,AR 智能眼镜的发展将重塑人类…

初识Vue2及MVVM理解

1、什么是Vue Vue是一款用于构建用户界面的JavaScript框架。它基于标准HTML、CSS和JavaScript构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;可以高效地开发用户界面。 Vue.js是一套构建用户界面的渐进式框架&#xff0c;采用自底向上增量开发的设计&…

Rust:专业级错误处理工具 thiserror 详解

Rust&#xff1a;专业级错误处理工具 thiserror 详解 thiserror 是 Rust 中用于高效定义自定义错误类型的库&#xff0c;特别适合库开发。相比 anyhow 的应用级错误处理&#xff0c;thiserror 提供更精确的错误控制&#xff0c;让库用户能模式匹配具体错误。 &#x1f4e6; 基…

Python网络爬虫(一) - 爬取静态网页

文章目录一、静态网页概述1. 静态网页介绍2. 静态网页爬取技术Requests介绍二、安装 Requests 库三、发送请求并获取响应1. 发送 GET 请求1.1 get() 方法介绍1.2 get() 方法签名介绍1.3 get() 方法参数介绍1.4 示例&#xff1a;发送get请求2. 发送 POST 请求2.1 post() 方法介绍…

.NET/C# webapi框架下给swagger的api文档中显示注释(可下载源码)

bg&#xff1a;.NET/C#真的是越来越凉了。用的是.net9&#xff0c;创建完自带一个天气预报api拿来测试就行 1、在Controllers中弄多几个&#xff0c;并写上注释 /// <summary> /// Post注释 /// </summary> /// <returns></returns> [HttpPost] publ…

2508C++,检测S模式

原文 可用Windows.System.Profile.WindowsIntegrityPolicy类检测S模式. //C# using Windows.System.Profile; if (WindowsIntegrityPolicy.IsEnabled) {//系统在S模式if (WindowsIntegrityPolicy.CanDisable) {//系统在S模式,但可退出S模式suggestCompanion true;} else {//系…

Coding Exercising Day 9 of “Code Ideas Record“:StackQueue part 01

文章目录1. Theoretical basisThe C standard library has multiple versions. To understand the implementation principles of stack and queue, we must know which STL version we are using.The stack and queue discussed next are data structures in *SGI STL*. Only …