推荐学习书目
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
oska874
V2EX  ›  Python

怎么把 python 打包成 exe 可执行文件?

  •  
  •   oska874 · Oct 25, 2015 · 12040 views
    This topic created in 3880 days ago, the information mentioned may be changed or developed.

    如题,自己写了个小程序,有两个源文件,用到了 tkinter 库,怎么打包成 exe 文件。用 pyinstaller 打包成一个文件,但是执行有问题:点击以下 button ,就会重复新建一个窗口程序。该怎么办?
    系统是 win10 64bit , python 是 2.7.10 。

    22 replies    2015-10-28 00:26:50 +08:00
    fullpowers
        1
    fullpowers  
       Oct 26, 2015 via Android
    试试 py2exe
    fullpowers
        2
    fullpowers  
       Oct 26, 2015 via Android
    对了, py2exe 打包非界面程序还是挺给力的。但我用 py2exe 打包带 tkinter 库的单一 exe 不能执行,非单一的就能,求解。
    g00001
        3
    g00001  
       Oct 26, 2015
    唉, python 生成 exe 这种简单的事真是让人头痛,没有 aardio 方便。
    aardio 里可以 py.exec( python 代码 ) 可以用来捆绑 python 生成独立 EXE ,不过 python 的确是,引用到 pyd 的生成独立 EXE 就容易出问题。
    owwlo
        4
    owwlo  
       Oct 26, 2015
    我也在用 pyinstaller 但是 UI 部分用的是 PyQt5+QtQuick 到目前为止都还不错,能详细描述下你的问题吗?
    oska874
        5
    oska874  
    OP
       Oct 26, 2015 via Android
    @owwlo 按一下按钮就重新打开一个窗口,而且只能从命令行启动。
    @fullpowers 我这就俩源文件,要打包成一个 exe ,用 py2exe 也一样。
    owwlo
        6
    owwlo  
       Oct 26, 2015
    @oska874 如果可以能贴下代码吗,还是不是很清楚
    iwj
        7
    iwj  
       Oct 26, 2015
    py2exe 没用过,不过,另外一个比这个更好用,而且生成的文件少。
    1 )在终端下安装 pip install pyinstaller 注意,后面有 er
    2 )用 cd 命令转到你的项目目录,如果要对 smart.py 进行打包,那么使用命令 pyinstaller -F smart.py
    -F 参数是表示生成单独的一个 exe 文件,你可以加和不加两种都试一下


    随便那么一写就写复杂了,于是又提炼了一个简洁的版本放在最前面,以下是详细的:

    推荐你用 PyInstaller3.0 ,我自己就在用,方便快捷。
    1 )官网是 http://www.pyinstaller.org/ 英文阅读水平好的话可以进去看看
    2 )在终端下安装 pip install pyinstaller 注意,后面有 er 如果没加 er 是另外一个包。安装这个包有个先决条件,不过使用 pip 命令如果你缺那个先行条件的包它会自动完成的,具体可以看对应的文档
    http://pythonhosted.org/PyInstaller/#id11
    这一步,我本机上实际用 pip 安装时加了 sudo 来装的,不加就无法正常安装。
    3 )用 cd 命令转到你的项目目录,如果要对 smart.py 进行打包,那么使用命令:
    pyinstaller -F smart.py
    这里的 -F 参数是表示生成单独的一个 exe 文件
    这一步对应的文档是 http://pythonhosted.org/PyInstaller/#using-pyinstaller
    iwj
        8
    iwj  
       Oct 26, 2015
    😓抱歉,看了你的标题,没看到你的描述。如果是像你描述的那样,建议检查代码。
    oska874
        9
    oska874  
    OP
       Oct 26, 2015
    @iwj 代码肯定没问题,直接用 python 执行都是正常的。
    oska874
        10
    oska874  
    OP
       Oct 26, 2015
    @iwj 按下按钮会用 multiprocess 新建一个子进程。
    @owwlo 代码 https://gist.github.com/oska874/e1deca4f2361c0daf40f
    jamiesun
        11
    jamiesun  
       Oct 26, 2015   ❤️ 1
    @owwlo

    参考一下 https://github.com/phuslu/pybuild

    可以解决你很多意外的问题。
    fangdingjun
        12
    fangdingjun  
       Oct 26, 2015
    修改你的 spec 文件或者使用命令行参数,添加 console=False
    exe = EXE(pyz,
    ...
    console=False,
    ...
    )
    aver4vex
        13
    aver4vex  
       Oct 26, 2015
    cxfreeze
    owwlo
        14
    owwlo  
       Oct 26, 2015 via iPhone
    原因是你用了 process … python 库在处理你的 process 的时候 fork 了一个父进程(这样才能在另一个进程里运行出自一个文件的代码),当你把程序打包成一个文件的时候这个父进程就是你所有的代码外加 python 运行环境也就导致了你启动 server 的时候系统会再创建一个实例的现象。

    解决方法
    1.用 thread (不知道你是否必须使用 process ?)
    2.可以再创建一个 python 脚本专门用来启动 server 进程,将这个脚本作为资源文件加入 pyinstaller ,这样当程序运行的时候这个脚本会被解压到临时目录…
    owwlo
        15
    owwlo  
       Oct 26, 2015
    然后在主程序里通过命令行调用启动这个脚本…但是我还没有想到好的来杀死这个脚本启动的进程方法
    leavic
        16
    leavic  
       Oct 26, 2015
    我 evernote 中记录的一个情况,是 py2exe 会默认少打包一个 dll 文件,包进去就可以了,不一定适用你的情况。
    ==================================================
    Thanks to this link, you have to edit site-packages/py2exe/build_exe.py and add "tcl85.dll" and "tk85.dll" to the dlls_in_exedir list. This will get it to run, although you'll still have the tcl folders, and those two dlls will be there along-side the exe. But it's way better than bundle_files=3.

    self.dlls_in_exedir = [python_dll,
    "w9xpopen%s.exe" % (is_debug_build and "_d" or ""),
    "msvcr71%s.dll" % (is_debug_build and "d" or ""),
    "tcl85.dll",
    "tk85.dll"]
    oska874
        17
    oska874  
    OP
       Oct 27, 2015
    @owwlo 在 windows 下怎么用安装 pyqt5 ,用 python 2.7 一块?
    owwlo
        18
    owwlo  
       Oct 27, 2015
    @oska874 pyqt5 最新的 windows 预编译版本是基于 python3.4 的,我用的环境: Python3.4.3 32bit* + pyinstaller3.0 + PyQt5.5

    *使用 3.4.3 是因为 PyQt5.5 的 pre-built 发行包基于 Python3.4 ,而 32bit 是由于我在代码中用了 bcrypt , bcrypt 安装时需要 msvc10 编译而 express 版的 msvc10 只包含 x86 编译器(也建议安装 32bit 的 python 因为有些库真的需要自己编译)。

    还有关于你上面那个问题,如果继续使用 tkinter 的话只要把所有的 mp.Process 改成 threading.Thread 并 import threading 就可以了
    Drahcir
        19
    Drahcir  
       Oct 27, 2015
    推荐使用 py2exe ,虽然只能用于 windows 平台,不过效果不错。
    我自己成功打包过用 wxPython 作界面的 python 程序。
    http://www.py2exe.org
    geeklian
        20
    geeklian  
       Oct 27, 2015
    说说我用在“生产”环境的歪门邪道吧。

    这里的生产环境,是我所在银行的上千台柜台电脑。

    简而言之:用一个绿色的 python 去执行 py 文件就行了。

    实现这个方法很简单:

    1. 你需要一个 Anaconda/ Anaconda3 / WinPython ,三者其一,创建一个绿色的 Windows Python 环境,所需的包健全。
    你可以在这两个网址下载他们:
    https://www.continuum.io/downloads
    https://winpython.github.io/

    2. 将你的程序放置成 这个样子:

    root
    -app
    --main.py
    -runtime
    --python.exe
    --.....

    然后修改 phuslu 大神的一个启动器,到你想要的形态,地址 https://github.com/phuslu/taskbar ,关闭这个启动器会帮你杀死子进程。也可以重启子进程....

    其实稍微会点.net , vb , vc 都能写出一个简单的启动器。

    缺点:

    目前看就是体积大,这个企业内网无视了。

    代码没法编译,这个其实 py2exe , cxfreeze 也很容易反编译,企业内部也无视了。

    优点:

    目前几乎没有 py2exe , cxfreeze , pyinstaller 这些的一切 bug 。中文路径没问题,中文文件名也没问题, QT5 无问题....反正一直使用还算良好。
    oska874
        21
    oska874  
    OP
       Oct 27, 2015
    @owwlo 果然,换成 threading 就正常了,不过有个问题,怎么杀死 threading ?、
    @geeklian 没看懂你的内容。 我这么做的目的就是避免在第三方电脑上安装 python ,即使绿色的也要避免。
    @fangdingjun 我试了把 console 改成 false ,但是启动的时候还是会弹出来一个 cmd 窗口,怎么去掉?
    owwlo
        22
    owwlo  
       Oct 28, 2015
    @oska874 python 并不提供 api 来杀死 thread ,因为 thread 是程序 process 的一部分,杀死可能会导致进程出现严重的错误。需要在代码里声明如何让线程退出。根据你的情况你在 start_transd 里面分别使用了 TftpServer 、 FTPHandler 和 HTTPServer ,需要针对每种 server 定义“停止”的方法。用 TftpServer 举例, http://tftpy.sourceforge.net/sphinx/, TftpServer 有 stop 方法,可以在 listen 的时候保存 TftpServer 的实例并在点击 stop 按钮的时候触发“ TftpServer 实例”.stop()
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5361 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 71ms · UTC 07:35 · PVG 15:35 · LAX 00:35 · JFK 03:35
    ♥ Do have faith in what you're doing.