Python 中如何直接 import 某个 dll

2021-01-04 13:15:45 +08:00
 RingSunKaiya
情况:最近在看别人写的代码,发现该目录下只有 dll 和 py 文件,而 Py 文件的开头直接 Import 了这个 dll 文件,通过__file__方法,查看到导入包的路径和名称就是这个 py 文件同目录下的 dll 。
问题:Python 可以直接 import 一个 dll 文件
请问这个 dll 文件是如何生成的,是什么原理?
是 Pythion 代码打包成 dll 还是用 C 写的 dll
在网上查了以下资料 Python import 模块有四种方法
1.使用 python 编写的.py 文件
2.把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py 文件,该文件夹称之为包)
3.使用 C 编写并链接到 python 解释器的内置模块
4.已被编译为共享库或 DLL 的 C 或 C++扩展

Python 引用 dll 是使用的 ctypes
5128 次点击
所在节点    Python
25 条回复
okcdz
2021-01-04 13:33:30 +08:00
dll 是 C 写的代码,导出的 C 的接口
Python 解释器 C 写的,调用 dll 不是什么怪事,比如 Windows 下用 LoadLibraryA 函数,mac 用 dyld 方法。

有两种方法:
1. 直接用 FFI 调 C 接口的话,直接调用 C 写的函数,不用为 Python 写适配代码,很方便,但是有一定开销。
2. 也可以导出为 Python 的格式,但是要写一些胶水代码,其实内部也是一个 dll 而已。
RingSunKaiya
2021-01-04 14:01:43 +08:00
Window 下 Python 调用 Dll 是 LoadLibrary(A),比如,是需要通过函数加载 Dll,才能使用,但现在的问题是 在 Python 脚本直接 import A,不用调用任何函数先加载 Dll 。
推测是先写的 Py 代码,然后转为 C 代码,最后打包成 Dll
详见 CSDN 上的一篇文章
https://blog.csdn.net/RingSunKaiya/article/details/112058851
dinjufen
2021-01-04 14:30:27 +08:00
之前写过一个 C++的 python binding,用的是 boost::python 相关的库,你只要遵循他的写法,就可以生成你说的这种 python 能直接 import 不需要其他操作的.pyd 文件( dll 也可)。
northisland
2021-01-04 15:12:27 +08:00
ctypes 大概是这样

from ctypes import CDLL

foo = CDLL("./build/libxxxx.so") # 载入库
ret = foo.func(keypoints_p) # 调用 c++库接口 (数据绑定需要 3 句话)
northisland
2021-01-04 15:15:50 +08:00
# 用 numpy 搞定内存分配,传递给 c 形式的动态库
c_float_p = ctypes.POINTER(ctypes.c_float) # 声明指针
keypoints = np.ndarray(shape=(68, 2), dtype=np.float32) # numpy 对象,传回的关键点数组
keypoints_p = keypoints.ctypes.data_as(c_float_p) # c++指针


最高赞的回答,就是 ctypes 的套路
https://stackoverflow.com/questions/5081875/ctypes-beginner
XIVN1987
2021-01-04 15:29:03 +08:00
虽然后缀名是 dll,,但文件内容可能是 pyd,,

毕竟后缀名可以随便改,,不能仅凭后缀名就断定文件内容
XIVN1987
2021-01-04 15:35:31 +08:00
@dinjufen

说到 boost::python,,那不如试试它的一个轻量级复制品,,

pybind11 is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. Its goals and syntax are similar to the excellent Boost.Python library by David Abrahams: to minimize boilerplate code in traditional extension modules by inferring type information using compile-time introspection.

header-only,没有依赖、简化配置、更易使用,,下面这个帖子里有我的编译方法,可以看到非常简单:

https://www.v2ex.com/t/740805
YaZuiBi
2021-01-04 15:43:51 +08:00
利用 C/C++创建 python 模块,里面用 LoadLibrary(动态链接库文件)加载动态链接库,然后打包成 xxx.pyd ,然后在 python 中 import xxx 就可以用。
ruanimal
2021-01-04 16:07:36 +08:00
@RingSunKaiya 和 linux 版 Python 直接 import so 是一个方法,用 c 写的代码 include python.h, 然后编译成动态库就可以了
ysc3839
2021-01-04 16:53:39 +08:00
估计是用 Python C API 写的 module,可以用纯 C 语言编写,也可以用 C++ 配合 pybind11 编写.
RingSunKaiya
2021-01-04 17:16:14 +08:00
@YaZuiBi
Python 文件转 pyd 很好实现
RingSunKaiya
2021-01-04 17:17:14 +08:00
@YaZuiBi 可以这样干?
RingSunKaiya
2021-01-04 17:27:38 +08:00
@ruanimal 然后就可以直接 import 这个 dll 了
ruanimal
2021-01-04 17:31:41 +08:00
@RingSunKaiya 对,可以参考 swig,用的是同一个思路
YaZuiBi
2021-01-04 20:18:51 +08:00
@RingSunKaiya 可以的,但是语法需要能够转成 Python 模块才行。

https://blog.csdn.net/pengyancai/article/details/54587955?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

另外你这里的.dll 文件,要是装了 VS,用
dumpbin.exe -exports xxx.dll 看看链接库的对外接口,防止这个文件不是真正的 dll 文件
RingSunKaiya
2021-01-04 21:33:31 +08:00
就是说.pyd 和.dll 以及.so 是没有太大的区别
linvaux
2021-01-04 22:04:37 +08:00
最近在做一个 sdk,加解密模块就是 py 编译成 so 和 pyd,然后导入的
no1xsyzy
2021-01-05 01:24:09 +08:00
@RingSunKaiya 我记得官网有句话,pyd 就是一个 dll,只不过改了个后缀名让它更容易被辨识,但并不影响它确实是个 dll
RingSunKaiya
2021-01-05 07:50:58 +08:00
3Q
RingSunKaiya
2021-01-05 09:30:52 +08:00
这样处理除了不让别人看到源码以外,还能提高速度吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/741469

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX