当前位置:首页>python>Python exe文件打包神器-Nuitka!

Python exe文件打包神器-Nuitka!

  • 2026-10-21 13:28:03
Python exe文件打包神器-Nuitka!

你有没有被同事问过一句: “能不能给我一个点两下就能跑的 exe,我电脑没装 Python 啊?”

每次听到这个,心里都在想:哥这是写脚本的,不是发安装包的工程师啊…但没办法,落到我们 Python 搬砖工头上,就是一个字:打包。

今天就聊一个我觉得还挺好用的东西:Nuitka,简单说,就是“把 Python 代码真·编译成 exe 的家伙”。

(顺嘴说一句,之前我写数据库选型的时候顺手测过一些性能场景,这个思路在这次也有点用)

先说一下为啥会注意到 Nuitka

大部分人接触打包,第一反应都是 PyInstaller,对吧。 确实也好用:一条命令出 exe,爽。

但用多了你会发现几个槽点:

  • 生成的 exe 特别大,一两百 M 起步
  • 启动时候要解压一堆东西,冷启动像卡了一下
  • 杀毒软件有时候还给你来个误报

很多场景无所谓,比如公司内部工具,大家都习惯了。 但要是给外部用户,或者要放到某些“敏感”环境里,就不太好看。

后来我才知道有这么个 Nuitka,定位就和 PyInstaller 不太一样。

一句话描述: PyInstaller:把 Python 解释器 + 你的代码 + 依赖,打一个大箱子。 Nuitka:把你的 Python 代码,翻译成 C 代码,再用正常 C 编译器编成真正的二进制。

所以,它更像是“编译器”而不是“打包器”。

Nuitka 大概能带来什么好处

别指望它能把屎山一夜之间变成高性能服务,但几个现实的好处还是有的:

  1. 真的编译成 native 代码 你的业务逻辑会跑在 C 里,不是单纯丢给解释器去一行行解。 CPU 密集型的地方会舒服一点,尤其是算法、循环比较多的脚本。

  2. 发布体验更接近“正经软件” 生成的是一个真正的 exe(或者 Linux 的 ELF),外观上跟 C++ 写的没啥差别, 很多安全软件对这类二进制的“警惕心”反而没那么高。

  3. 依赖打包更干净 它走的是 CPython 的 ABI,兼容性也不错,适合你项目里各种第三方轮子一大堆的情况。

  4. 一次配置好,后面就当命令行工具用 习惯之后,其实比起手动折腾 PyInstaller 的 spec 文件,要清爽一点。

先来一个最小例子:把 hello.py 编成 exe

先确保你本地 Python 是 3.x,版本不要太老。 然后安装 Nuitka:

pip install -U nuitka

在 Windows 上,还需要有个 C 编译器。 最常见的就是装一个 Visual Studio Build Tools(只勾选 C++ 相关组件就行), 或者装 MinGW-w64 也可以,这块就不展开啰嗦了。

随便写个小脚本 hello.py:

# hello.py
import sys
from datetime import datetime

defmain():
    print("Hello, Nuitka!")
    print("Python version:", sys.version)
    print("Now is:", datetime.now())

if __name__ == "__main__":
    main()

用 Nuitka 编译:

python -m nuitka --onefile hello.py

跑完之后,你会在当前目录看到一个 hello.exe(Windows), 双击一下,弹出个控制台窗口,内容跟你在 python hello.py 时一样。

这里几个小点:

  • python -m nuitka:相当于把 Nuitka 当模块调用
  • --onefile:打成单文件 exe,方便拷来拷去
  • 不加 --onefile 的话,它会生成一个目录 + exe,启动更快,但东西多一点

稍微像个“工具”的例子:一个小命令行脚本

很多人真实需求是做一个小工具,比如批量改文件名、发 HTTP 请求、查点什么东西。

举个简单点的例子:写个命令行脚本,帮你把一个目录下所有 .txt 文件改成 .bak。

# rename_txt.py
import argparse
import pathlib

defrename_txt_to_bak(folder: str) -> None:
    base = pathlib.Path(folder)
ifnot base.exists():
        print(f"路径不存在:{base}")
return

    count = 0
for p in base.rglob("*.txt"):
        new_name = p.with_suffix(".bak")
        p.rename(new_name)
        count += 1

    print(f"处理完成,一共改名 {count} 个文件")

defmain():
    parser = argparse.ArgumentParser(description="批量把 .txt 改成 .bak 的小工具")
    parser.add_argument("folder", help="目标目录路径")
    args = parser.parse_args()

    rename_txt_to_bak(args.folder)

if __name__ == "__main__":
    main()

打包命令也很简单:

python -m nuitka --onefile rename_txt.py

生成的 rename_txt.exe 丢给测试同事,让他在自己的 Windows 上打开 cmd 这样用:

rename_txt.exe D:\logs

他完全不用关心什么 Python 解释器、虚拟环境,照样跑。

再来个带三方库的例子:requests + 简单重试

很多业务脚本会发 HTTP 请求,我们就做个小一点的“接口探活工具”。

# ping_url.py
import argparse
import time
import requests

defping(url: str, attempts: int = 3, interval: float = 1.0) -> None:
for i in range(1, attempts + 1):
try:
            resp = requests.get(url, timeout=3)
            print(f"[{i}] {url} -> {resp.status_code}")
except requests.RequestException as exc:
            print(f"[{i}] {url} 请求失败:{exc}")
        time.sleep(interval)

defmain():
    parser = argparse.ArgumentParser(description="简单的 HTTP 探活小工具")
    parser.add_argument("url", help="目标 URL")
    parser.add_argument("-n", "--attempts", type=int, default=3, help="重试次数")
    parser.add_argument("-i", "--interval", type=float, default=1.0, help="重试间隔秒数")
    args = parser.parse_args()
    ping(args.url, args.attempts, args.interval)

if __name__ == "__main__":
    main()

因为用到了 requests,强烈建议先建个虚拟环境,只装项目需要的依赖:

python -m venv venv
venv\Scripts\activate  # Windows

pip install -U pip
pip install requests nuitka

然后在虚拟环境里编译:

python -m nuitka --onefile ping_url.py

这样打出来的 exe 里只会带上你这个环境里的包,体积和冗余都会好一点。

常用几个 Nuitka 参数,大概知道一下就够

别被一大片参数吓到,最常用的就那几个:

  • --onefile单文件打包,适合发给别人。换成 --standalone 就是目录模式。

  • --windows-disable-consoleWindows 下如果你做的是 GUI 程序,不想弹黑框,就加这个。 比如你用 Tkinter / PyQt 做了个小工具:

    python -m nuitka --onefile --windows-disable-console main_gui.py
  • --include-data-dir / --include-data-file有时候你要带上模板文件、图片之类的静态资源,可以这样:

    python -m nuitka --onefile ^
        --include-data-dir=assets=assets ^
        main_gui.py

    这个写法的意思是:把工程里的 assets 目录原样打包进去, 运行时也保持 assets 这个路径。

  • --enable-plugin=比如你用的是 PySide6、PyQt5 这种 GUI 库, Nuitka 自己搞了一堆 plugin,帮你处理各种奇怪的导入方式:

    python -m nuitka --onefile ^
        --enable-plugin=pyside6 ^
        main_gui.py

一般来说,遇到框架级别的库(Django / Flask / PySide / PyQt 之类), 在官方文档里搜一下 “Nuitka plugin xxx” 基本都有对应示例。

和 PyInstaller 比到底差在哪、强在哪

日常使用感受,粗暴对比一下:

  • 速度方面: CPU 密集的脚本,Nuitka 编译后基本都能比纯解释执行快一些, I/O 密集和网络调用那种,就别指望有奇迹了,网络延迟谁也改变不了。

  • 打包体验: PyInstaller 上手快,遇到各种“找不到模块”就开始加隐藏导入、调 spec; Nuitka 初次配置麻烦一点(特别是编译器那块), 但后面参数稳定下来,就像正常编译 C 项目一样重复使用。

  • 体积: 这俩其实都不算小,看项目依赖。 Nuitka 有时候会稍微好看一点,但也别指望一个几十行脚本打完只有几百 K。

  • 适用场景:

    • 快速给测试/运营一个工具,图省事:PyInstaller 完全够用
    • 想要“更像原生程序”、对性能稍微敏感点:可以考虑 Nuitka
    • 你本来就喜欢折腾编译器、构建流程:Nuitka 会更对胃口

几个容易踩的小坑,提前心里有数

随便提醒几个常见问题,免得你调一下午:

  1. “为啥我在自己电脑能跑,打完给别人的电脑提示找不到 xxx.dll?”

    • 尽量在干净环境下编译(虚拟环境、甚至专门的构建机)。
    • 不要把一大坨跟项目无关的东西也塞进去。
  2. “exe 太慢了,是不是我用错参数了?”

    • 先别上来就 --onefile,先用目录模式 --standalone 看下启动速度。
    • 单文件模式本身就要解压,会比目录模式慢一点,这很正常。
  3. “杀毒软件说我可疑程序,咋办?”

    • 这个谁都避免不了…
    • 尽量用官方 Python + 合法签名证书(如果公司有的话),
    • exe 建议走公司内网分发,别随便丢网盘给陌生人。
  4. “编译太慢了,每次改几行都要等半天”

    • 调试阶段可以先直接跑 .py,确认逻辑没问题再编译。
    • 想要频繁改又频繁出 exe 的场景,本身就比较折磨,工具再好也救不了太多。

什么时候值得你认真学一下 Nuitka

如果你平时就写一些一次性的脚本,其实完全没必要专门学它,PyInstaller 甚至 zip 打包扔给会用 Python 的同事就够了。

但下面几种情况,我觉得还是挺值得折腾一下的:

  • 有一堆内部工具,希望统一打成“一个 exe 发给所有人”那种
  • 有 CPU 比较重的逻辑,想少买一点服务器,提升点吞吐
  • 公司有要求:发给客户的东西不能是纯脚本,要是“编译产物”
  • 对“构建链路”有点洁癖,想把 Python 项目的发布流程做得更像 C/C++ / Go 那种

Nuitka 不是什么银弹,但它确实把“Python 只能当脚本语言”的那层壳,掀开了一点点。 你会发现:原来 Python 也可以踏踏实实编成一个像样的程序,对运维、对测试、对你的甲方,都友好一些。

行,差不多就聊到这儿。 你要是正好手上有个 Python 小工具迟迟懒得打包,不如现在随手装个 Nuitka,挑个脚本试一把,踩踩坑比啥都实际。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥私藏精品🔥
虎哥作为一名老码农,整理了全网最全《Python高级资料合集》。总量高达650GB

最新文章

随机文章