使用cs_freeze打包Python为exe后遇scipy.spatial.ckdtree模块未找到错误
嘿,这个问题我熟!很多人用cx_Freeze打包带scipy的Python程序时都会踩这个坑,核心原因就是cx_Freeze默认没法自动识别scipy这类库的二进制扩展文件——你看到的ckdtree.cp36-win32.pyd其实就是Windows平台下的Python扩展模块(相当于Linux里的.so文件),但cx_Freeze没把它自动包含进打包后的程序里。
给你几个亲测有效的解决办法:
方法1:在setup.py里明确指定要包含的模块
直接修改你的cx_Freeze打包脚本setup.py,在build_exe选项里添加includes参数,把scipy.spatial.ckdtree和scipy本身都列进去,让cx_Freeze主动去找这个模块。示例代码如下:
from cx_Freeze import setup, Executable # 替换成你的主程序文件名 target = Executable(script="your_main_script.py") setup( name="你的程序名", version="1.0", description="程序描述", executables=[target], options={ "build_exe": { "includes": ["scipy.spatial.ckdtree", "scipy"], # 要是后面还缺其他scipy模块,直接往这里加就行 } } )
改完后重新运行python setup.py build打包,这次cx_Freeze就会把ckdtree的.pyd文件一起打包进去了。
方法2:手动复制.pyd文件到exe目录
如果方法1没搞定,那就来个简单粗暴的:找到你Python安装目录下Lib\site-packages\scipy\spatial里的ckdtree.cp36-win32.pyd文件,手动复制到打包后生成的exe所在的build\exe.win32-3.6\Lib\scipy\spatial目录里(路径根据你的Python版本和打包输出位置调整),复制完再运行exe试试,大概率就能正常跑了。
方法3:用include_files参数自动复制文件
要是不想手动复制,也可以在setup.py里用include_files参数直接指定要打包的.pyd文件路径,这样打包时会自动把它复制到对应目录。示例代码:
import os import scipy # 其他参数不变 setup( # ... 这里填你的name、version等信息 executables=[target], options={ "build_exe": { "include_files": [ os.path.join(os.path.dirname(scipy.__file__), "spatial", "ckdtree.cp36-win32.pyd") ] } } )
另外提个小注意点:你用的是Python3.6,对应的cx_Freeze版本最好选5.x系列,因为高版本的cx_Freeze已经不再支持Python3.6了,版本不兼容也可能导致这类模块找不到的问题哦。
内容的提问来源于stack exchange,提问作者Abin John Thomas

