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
LeeReamond
V2EX  ›  Python

Python 现代化打包应用到 exe 的方式?

  •  
  •   LeeReamond · 2022-06-12 20:34:14 +08:00 · 6301 次点击
    这是一个创建于 921 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前一段时间看到 PyOxidizer 这个项目,但是大概看了看文档也没看懂,看起来似乎是个打包程序,但似乎要和 rust 关联,我想打包 python 程序为什么和 rust 产生关系了?

    pyinstaller 打包方式已经持续多年了,比如一个简单的需求是,我有一个 main.py 的程序,有若干 pip 依赖,我现在希望产生一个 exe ,让它在没有安装 python 的电脑上也能运行。pyinstaller 能用,但是实在也说不上好用,隐藏源码之类的功能就不奢求了,打包完后提示缺少依赖也是常事,在加上启动速度实在不敢恭维。

    py 虚拟机相对于 java 虚拟机启动起来还是要快一些,比如运行

    python -c "print('hello world')"
    

    这种命令无论在 win 还是 linux 上都可以 0.1 秒内返回结果。而 venv 之类的虚拟环境本身体积也不是很大,大概只有十几 MB ,为啥不能有个好用的打包系统。。。后来有个 nuitika 打包,但是还是使用起来不方便,我想随手发布个小脚本,打包还要 gcc 环境。。

    27 条回复    2022-06-20 17:51:34 +08:00
    nexply1920
        1
    nexply1920  
       2022-06-12 20:50:39 +08:00
    坐等大佬
    ClericPy
        2
    ClericPy  
       2022-06-12 20:52:47 +08:00
    呃, 巧了... 我今晚上刚发出去一个 GUI 帮着用 nuitka 打包的, 拖延了一年多昨晚上整理 GTD 时候看到

    代码质量很渣, 也就是个能用的原型阶段, 可以参考一下, 主要就是记不住那么多参数和文档, 以及依赖源码分离打包

    https://github.com/ClericPy/nuitka_simple_gui
    lifansama
        3
    lifansama  
       2022-06-12 21:17:11 +08:00 via Android
    @ClericPy 能请教一个问题吗,--nofollow-imports 的作用是什么?在 nuitka 的 User Manual 里没有找到这个参数
    ClericPy
        4
    ClericPy  
       2022-06-12 21:31:30 +08:00
    @lifansama 为了依赖和源码分离, 依赖我通过 pip install -t xxx 的方式直接丢进去, 不然编译太久了, 之前编译 psutil 啥的没等死我...
    jeeyong
        5
    jeeyong  
       2022-06-12 21:37:31 +08:00
    我一直用 pyinstaller 打包的啊..
    如果你都打包到一个文件里, 启动速度就会慢. 他要先解压缩到一个系统临时目录.
    不用-F 参数, 就没啥事啊..
    至于缺少依赖的事情...有几个参数可以快速打包好.
    我发布过的最复杂的应用是打包 chromium, requests, pyqt, pymysql, xpinyin, cchardet, pyquery, win32api, psutil.
    总共 800 多 MB
    saucerman8
        6
    saucerman8  
       2022-06-12 21:45:55 +08:00
    @jeeyong #5 我之前用 pyinstall 打包一个 flask 写的最简单的 web app ,启动特别慢,用不用-F 都很慢,不知道为啥。。后来放弃了
    Buges
        7
    Buges  
       2022-06-12 22:00:30 +08:00 via Android
    是的,Python 打包很难用。你费半天劲打包好了,扔 musl 的发行版上一跑,还是跑不起来。
    我更希望 Python 能有类似前端 webpack/rollup 那样的打包,能把代码包括依赖 bundle 起来,并 transpile 到兼容低版本运行环境的代码。要是还能妥善处理 native 依赖(按需安装或构建)就更好了。
    makelove
        8
    makelove  
       2022-06-12 22:04:08 +08:00   ❤️ 2
    折腾这个不如换个真编译语言,学个 go 也就三天功夫就能开写,你找完美打包可能也要这么长时间别提还不是完美方案
    pursuer
        9
    pursuer  
       2022-06-12 22:21:02 +08:00
    python 设计时就更倾向于模块复用,不怎么考虑打包。还是让用户 pip install -r requirements.txt 吧 。如果用户不会,那说明他不是你的目标用户吧(玩笑
    Osk
        10
    Osk  
       2022-06-12 22:23:54 +08:00
    如果是 Windows, 也许考虑下 python embedded zip 版本, 此版本没有带 tk 等 GUI, 我没尝试过安装.

    用 embedded zip 版, 先改一点配置, 并安装上 pip, 然后, pip 安装依赖.

    接下来, 直接使用这个 python 环境进行开发. 等要发布正式版本时, 将 site-packages 压缩成 zip (可选, 压缩的好处是减少小文件, 节省体积), 写个 bootstrap 脚本(cmd/bat), 调用这个 python 执行自己的脚本即可.

    如果有需要, 可以将自己的源代码编译成 pyc, 项目的依赖也可以编译后压缩成 zip.


    最终, 依赖引入配置里面包含:
    python.zip: 嵌入发行版自带的标准库 zip.
    site.zip : pip 安装的第三方依赖, 自行打包 zip.
    project_deps.zip : 项目依赖, 自行打包.



    好处是: 真的不会有依赖问题.
    缺点是: 文件相对比大一点, 且不是一个 exe (虽然你可以用 rar 等工具创建 sfx), bootstrap 脚本需要一点 cmd 脚本知识, 没写好容易启动不了(比如空格等问题).




    至于 linux: 告辞, 生态碎成渣, 没有, 不然也就不会出现 docker, snap, flatpak 等奇奇怪怪的东西了
    jeeyong
        11
    jeeyong  
       2022-06-12 23:08:09 +08:00
    @saucerman8 哦? 我试试
    fuis
        12
    fuis  
       2022-06-12 23:13:52 +08:00
    stefwoo
        13
    stefwoo  
       2022-06-12 23:30:48 +08:00
    我感觉弄成 docker 还简单点。
    libaili
        14
    libaili  
       2022-06-12 23:40:46 +08:00
    @stefwoo 说的不是一回事,docker 多用于服务端,楼主说的是客户端
    ClericPy
        15
    ClericPy  
       2022-06-12 23:50:24 +08:00   ❤️ 1
    看到楼主提到 venv, 如果客户端那边有 python 解释器, 可以考虑走 zipapp + zipimport 的路子, 目前我平时用的就是 shiv 和我自己写的 zipapps, 貌似还有个 pex

    https://github.com/ClericPy/zipapps

    zipapps 几个参数可以注意一下, 也勉强能用来发布客户端:

    0. 如果对方没有 python 解释器, 也可以用官网那个 embed 嵌入式的绿色版解释器, 不过 -p 的 shebang 似乎只对 pylauncher 那个有用, 得自己写个启动 bat
    1. -o 的时候后缀把 .pyz 改成 .py, 这样子 Windows 上只要双击就行了
    2. -u=* 这样会把所有代码都解压出来, 避免一些相对路径导入的问题, 或者动态链接库的导入问题, 或者 -u=AUTO 自动判断 .pyd 如果不存在就不解压了
    3. -d 这个参数是在运行的时候安装依赖, 一开始是用来做跨平台发布(因为只和客户端有关), 而且节省打包后的 zip 大小, 并且依赖没变的话不会重新安装. 不过鉴于 embed python 没有 pip, 还要配合 ensure pip 参数, 有点麻烦, 当然如果对方是官网的 python 解释器自带 pip 就没事
    4. 当然如果对方不但有 venv 也可以直接用里面的 python.exe 来执行 pyz 文件, 依赖就不用打了

    不过多数情况还是拿来云原生上发布使用, 今天写 nuitka 那个 GUI 就是为了取代 zipapps 的习惯
    PMR
        16
    PMR  
       2022-06-13 01:58:42 +08:00 via Android
    用 cy 编译下 在用 pyinstaller 打包 不打包单文件速度还行 就单文件解压要时间
    610915518
        17
    610915518  
       2022-06-13 09:52:11 +08:00
    打包成单文件的话启动的确会慢些,试试 pyinstaller xx.py ,不带 -F 参数。缺少依赖就缺啥补啥,其实可以玩玩 go 语言,开发一些小脚本也是很快的
    frisktale
        18
    frisktale  
       2022-06-13 14:41:53 +08:00
    要不来玩玩.net 6 吧,我上周帮别人写了个统计 excel 数据的小程序,发布成单文件也就 20m
    fbichijing
        19
    fbichijing  
       2022-06-13 16:38:25 +08:00
    我平时的打包方式:

    Window10, python 3.8

    pyinstaller -D 多文件
    + nsis 如果有必要的话。

    确实,自己写的时候舒服,打包给别人用的时候麻烦。体态臃肿多少感觉丑陋...但考虑到节省了自己很多时间——不管是 code 还是别的——也就不去多想了。
    muzuiget
        20
    muzuiget  
       2022-06-13 20:14:12 +08:00
    因为 Python 的模块系统,语义上就是依赖了文件系统的。

    比如说代码中用了 __dir__ 或者 __file__ 这种变量,当打包变成单一执行文件时,这个变量怎么处理呢?是不是要把所有代码一一改写?如果不改写,那么只能打包了一个真的文件系统了,也就是所谓单一执行文件,就是一个自解压程序,启动当然慢。

    所以我觉折腾 Python 打包器都是浪费时间,太难做到完美,老老实实让用户先装一个 Python 环境不就好,Windows 10 商店有 Python 官方发布的程序,一键安装和卸载。
    1779930755cmy0
        21
    1779930755cmy0  
       2022-06-14 10:37:07 +08:00   ❤️ 3
    就我的经验来说,@Osk 这位老哥的办法是最简单、可操作性最强且不容易出问题的,我在这里稍微补充一点细节:
    1. 从 python 官网下载 embedded 版本的 python 压缩包,目前最后支持 win7 的版本是 3.8 ,我个人用的是 3.8.7 。
    2. 解压 python embedded 压缩包(假设解压到 c:/python )以后,找到 [python38._pth] 这个文件并打开,去掉 [import site] 前面的 [#] 。
    3. 下载 [get-pip.py] 文件,放到 python 文件夹里,打开 cmd ,进入 c:/python 目录,执行 python get-pip.py ,跑完以后 python embedded 就有了使用 pip 安装模块的能力,之后就可以在 pycharm 中安装模块了,比如 pyqt5 。如果使用 cmd 安装模块,需要先 cd c:/python ,然后 python -m pip install 模块名。
    4. 写程序的过程中要注意,在 main.py 中引用自己写的.py 文件时可能会失败,这是环境变量的问题,我的解决办法是在程序开头添加临时环境变量,如果自己写的需要引用的.py 文件跟 main.py 在同一路径下的话,可以这么写:
    import sys
    sys.path.append(os.path.dirname(os.path.abspath(__file__))),这一句的意思是把 main.py 所在路径临时添加到系统变量中。
    5. 写完 python 程序以后,写一个批处理 bat 文件,假设文件名为“启动程序.bat”,用来执行 main.py 程序,这是因为环境变量里没有嵌入式 python 的路径,需要指定 python.exe 的路径。一个简单的写法如下:
    cd c:/python
    python "c:/python/Projects/hello world/main.py"
    pause
    6. 如果不喜欢程序打开后伴随的 cmd 控制台窗口,可以去搜索隐藏控制台的 bat 代码,写在“启动程序.bat”开头即可。
    7. 将整个 python 文件夹压缩,发给其他人,随便他解压到哪个地方,只要双击“启动程序.bat”,就能运行你写好的 py 程序,到此真正实现免配置、便携化 python 程序的目的。
    1779930755cmy0
        22
    1779930755cmy0  
       2022-06-14 12:05:50 +08:00
    ungrown
        23
    ungrown  
       2022-06-14 14:31:34 +08:00
    @Buges #7 pyinstaller 不支持 musl 吗,我没玩过,问问
    LeeReamond
        24
    LeeReamond  
    OP
       2022-06-14 21:58:23 +08:00
    @1779930755cmy0 感觉不错,通用性很强,但是 bat 启动软件可能给用户观感比较差,大家还是感觉 exe 比较正规
    Osk
        25
    Osk  
       2022-06-16 19:14:33 +08:00
    @LeeReamond WinRAR 打包成 exe, 设置好 logo, 启动文件, 就成了 exe 了.
    或者找一个安装框架, 给桌面 /开始菜单创建一个快捷方式也行.
    再不济, 用其他语言编译个 exe 启动器也行

    /狗头 /
    bluehammer2019
        26
    bluehammer2019  
       2022-06-17 19:25:08 +08:00 via iPhone
    remrem
        27
    remrem  
       2022-06-20 17:51:34 +08:00
    @1779930755cmy0 感谢你和 osk 的分享,很实用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4533 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:59 · PVG 17:59 · LAX 01:59 · JFK 04:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.