V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
RingSunKaiya
V2EX  ›  Python

Python 中如何直接 import 某个 dll

  •  
  •   RingSunKaiya · 2021-01-04 13:15:45 +08:00 · 5103 次点击
    这是一个创建于 1427 天前的主题,其中的信息可能已经有所发展或是发生改变。
    情况:最近在看别人写的代码,发现该目录下只有 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
    25 条回复    2021-01-05 12:17:36 +08:00
    okcdz
        1
    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
        2
    RingSunKaiya  
    OP
       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
        3
    dinjufen  
       2021-01-04 14:30:27 +08:00
    之前写过一个 C++的 python binding,用的是 boost::python 相关的库,你只要遵循他的写法,就可以生成你说的这种 python 能直接 import 不需要其他操作的.pyd 文件( dll 也可)。
    northisland
        4
    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
        5
    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
        6
    XIVN1987  
       2021-01-04 15:29:03 +08:00   ❤️ 2
    虽然后缀名是 dll,,但文件内容可能是 pyd,,

    毕竟后缀名可以随便改,,不能仅凭后缀名就断定文件内容
    XIVN1987
        7
    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
        8
    YaZuiBi  
       2021-01-04 15:43:51 +08:00
    利用 C/C++创建 python 模块,里面用 LoadLibrary(动态链接库文件)加载动态链接库,然后打包成 xxx.pyd ,然后在 python 中 import xxx 就可以用。
    ruanimal
        9
    ruanimal  
       2021-01-04 16:07:36 +08:00
    @RingSunKaiya 和 linux 版 Python 直接 import so 是一个方法,用 c 写的代码 include python.h, 然后编译成动态库就可以了
    ysc3839
        10
    ysc3839  
       2021-01-04 16:53:39 +08:00
    估计是用 Python C API 写的 module,可以用纯 C 语言编写,也可以用 C++ 配合 pybind11 编写.
    RingSunKaiya
        11
    RingSunKaiya  
    OP
       2021-01-04 17:16:14 +08:00 via Android
    @YaZuiBi
    Python 文件转 pyd 很好实现
    RingSunKaiya
        12
    RingSunKaiya  
    OP
       2021-01-04 17:17:14 +08:00 via Android
    @YaZuiBi 可以这样干?
    RingSunKaiya
        13
    RingSunKaiya  
    OP
       2021-01-04 17:27:38 +08:00 via Android
    @ruanimal 然后就可以直接 import 这个 dll 了
    ruanimal
        14
    ruanimal  
       2021-01-04 17:31:41 +08:00
    @RingSunKaiya 对,可以参考 swig,用的是同一个思路
    YaZuiBi
        15
    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
        16
    RingSunKaiya  
    OP
       2021-01-04 21:33:31 +08:00 via Android
    就是说.pyd 和.dll 以及.so 是没有太大的区别
    linvaux
        17
    linvaux  
       2021-01-04 22:04:37 +08:00 via iPhone
    最近在做一个 sdk,加解密模块就是 py 编译成 so 和 pyd,然后导入的
    no1xsyzy
        18
    no1xsyzy  
       2021-01-05 01:24:09 +08:00
    @RingSunKaiya 我记得官网有句话,pyd 就是一个 dll,只不过改了个后缀名让它更容易被辨识,但并不影响它确实是个 dll
    RingSunKaiya
        19
    RingSunKaiya  
    OP
       2021-01-05 07:50:58 +08:00 via Android
    3Q
    RingSunKaiya
        20
    RingSunKaiya  
    OP
       2021-01-05 09:30:52 +08:00 via Android
    这样处理除了不让别人看到源码以外,还能提高速度吗?
    RingSunKaiya
        21
    RingSunKaiya  
    OP
       2021-01-05 12:15:13 +08:00 via Android
    @dinjufen 直接 import dll 的话 其实内部引用的是同名的 pyx,我把后缀 dll 改为 pyx,提示找不到模块,我把 dll 改为 pyd,就可以了,所以说应该是用 Python 代码转的 pyd,然后再改为 dll
    RingSunKaiya
        22
    RingSunKaiya  
    OP
       2021-01-05 12:16:00 +08:00 via Android
    @dinjufen 直接 import dll 的话 其实内部引用的是同名的 pyx,我把后缀 dll 改为 pyx,提示找不到模块,我把 dll 改为 pyd,就可以了,所以说应该是用 Python 代码转的 pyd,然后再改为 dll
    @XIVN1987
    ysc3839
        23
    ysc3839  
       2021-01-05 12:16:31 +08:00 via Android
    @YaZuiBi 只是看 DLL 导出符号的话不需要安装 VS,可以使用 https://github.com/lucasg/Dependencies
    RingSunKaiya
        24
    RingSunKaiya  
    OP
       2021-01-05 12:16:34 +08:00 via Android
    @dinjufen 直接 import dll 的话 其实内部引用的是同名的 pyx,我把后缀 dll 改为 pyx,提示找不到模块,我把 dll 改为 pyd,就可以了,所以说应该是用 Python 代码转的 pyd,然后再改为 dll
    @YaZuiBi
    RingSunKaiya
        25
    RingSunKaiya  
    OP
       2021-01-05 12:17:36 +08:00 via Android
    毕竟 py 转 pyd 很好实现
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5029 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 04:00 · PVG 12:00 · LAX 20:00 · JFK 23:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.