Python 实现动态链接库效果
需求来源是做OSM
编辑项目中要用Python 对.osm
文件进行校验,但是嘞,我的Python 代码
是需要用Nuitka 打包成二进制的,而校验规则又可能会随时调整,每次增减规则都要重新打包的话非常浪费时间。因此,便想能否通过类似与调用.dll
一样来动态加载.py
文件(伪动态链接库)。
前置要求
- Nuitka 打包后的二进制文件要包含完整的Python 运行时;✅
.py
文件要有统一的入口函数;✅.py
文件的依赖项要提前在二进制文件中import
。✅
实现代码
演示代码主要分为主文件main.py
和库文件ddl.py
,二者在相同目录:
# main.py
import os
import uuid
import importlib.util
### 调用外部.py 前的准备工作 ###
import numpy as np # 外部模块中需要用到的依赖项,需要提前导入准备
module_path = os.path.abspath("dll.py") # 获取目标.py 文件的绝对路径(此处可以读取该目录下的所有.py 文件,循环导入)
module_name = f"_dynamic_module_{uuid.uuid4().hex}" # 生成随机的模块名
# 模块名作为模块身份的唯一标识,仅会被导入一次,通过随机化处理可以避免命名重复而无法导入
spec = importlib.util.spec_from_file_location(module_name, module_path) # 创建一个加载说明(描述符)
module = importlib.util.module_from_spec(spec) # 根据加载说明加载.py 文件为模块
spec.loader.exec_module(module) # 执行模块
# 使用模块中的函数
module.hello() # 有必要约定模块中的函数签名保持一致,否则可能会报错
以下是库文件
# dll.py
import numpy as np # numpy 需要提前打包在二进制文件中
def hello():
print("Hello from dll.py!")
通过python -m nuitka --clang --standalone --onefile main.py
即可打包成二进制文件,即便在没有安装Python 环境的机器上也可以运行了。
$ ./main.bin
Hello from dll.py!