【问题标题】:Python - create an EXE that runs code as written, not as it was when compiledPython - 创建一个运行代码的 EXE,而不是编译时的代码
【发布时间】:2016-03-10 02:30:10
【问题描述】:

我正在制作一个模块化的 pygame 程序。我正在使用文件 main.py 的 pygame2exe 构建一个 exe,它基本上只是导入真正的主游戏并运行它。我希望的是一种能够从 EXE 执行 Python 脚本的启动器,而不是包含所有不可变文件的单个程序。

解决此问题的最佳方法是什么?我尝试使用 imp 在运行时动态导入所有模块,而不是隐式导入它们,但这似乎破坏了对象继承。

【问题讨论】:

  • 如何制作exe?如果你使用 py2exe,有​​一个语法。
  • 是的,我正在使用 py2exe,它的语法是什么?
  • 你知道 IDLE 会这样做,idle 的可执行文件只是从标准库中的idlelib 导入 stuf 并运行它,我想你同样需要一个转发到实际程序的 exe
  • bundle_files=3 给了我这个错误:AttributeError: Module instance has no attribute '__pydfile__'

标签: python pygame executable launcher dynamic-import


【解决方案1】:

经过一些实验,我找到了解决方案。

  1. 在应用程序的主文件夹中创建一个单独的文件夹source。这里将放置源文件。还将文件__init__.py 放到文件夹中。让我们将一个主文件命名为main_module.py

  2. 将其所有内容作为数据文件添加到 py2exe 配置 setup.py。现在程序编译完成后,这些文件将放在 dist 文件夹中。

    data_files += [('source', glob('source/*.py'),)]
    setup(
          data_files=data_files,
          ....  # other options
         windows=[
              {
                "script": "launcher.py",
                "icon_resources": [(0, "resources/favicon.ico")]
              }
         )
    
  3. Make launcher.py - 它的任务是导入所有系统和所需的库,如 pygame、pyqt 等。然后运行你的程序:

    import sys, time, os, hashlib, atexit  # std modules
    import PyQt5, ...   # foreign libraries
    sys.path.insert(0, 'source')
    exec('import main_module')
    
  4. 现在main_module.py 将被导入,如果它导入您的模块,它们也将被导入到它们在层次结构中的位置。比如main_module.py的头可以是这样的:

     import user_tweaks
     from user_data import parser
    

    这些文件user_tweaks.pyuser_data.py 应位于source 文件夹中相对于main_module.py 的适当路径中。

您可以更改source 文件夹的内容,而无需重新编译程序本身。任何时候程序运行它都会使用 source 的新内容。

因此,您的应用程序文件夹包含:

  • 单独的启动器 - 简单的 .exe 文件
  • 所有必需的模块
  • 您的应用程序及其所有模块。

【讨论】:

  • 我可以用这种方式加载每个文件吗?
  • 是的,我已经更新了配方以加载文件夹中的所有文件。
  • 不,这似乎仍然不是我想要的。我需要一个基本上运行“python main.py”而不需要安装 Python 和所有库的程序。我无法从中导入,我必须将文件添加到 setup.py。如果用户添加文件,但修改代码以导入文件怎么办?这不仅仅是一些一旦调用就必须执行的代码列表,它是需要导入的模块,是对象层次结构的一部分,并且在 exe 运行时甚至可能不存在的文件中多次使用编译。
  • 如果在源代码中传播应用程序怎么办?用户可以轻松地对其进行编辑、应用补丁等等?
  • 我快到了!我只是在从子包导入时遇到了一些麻烦。在我的 main.py 中,它导入了 source.menu.main_menu,但是当我从启动器运行它时,它给了我错误 ImportError: No module named source.menu.main_menu
【解决方案2】:

去年夏天我一直在努力解决同样的问题 - 从 python 脚本构建单个 .exe。但是没有 PyGame,但是有一个 PyQt5,这增加了一些类似的问题。纯标准工具都没有帮助我。

最后我用chaine解决了这个问题:make + Py2exe + 7Zip + Resource Hacker。这套系统给了我一个 .exe 和所有板载资源,不需要安装 - 所以你可以把它放在 windows 盒子上的任何地方并运行。

这里有详细文章:exe built with cx_Freeze, PyQt5, Python3 can't import ExtensionLoader_PyQt5_QtWidgets.py and run

请随时提出任何问题。

【讨论】:

  • 这个 EXE 会在不需要重新编译的情况下运行对脚本文件的任何更改吗?我并不是想获得一个封装所有 python 文件的 EXE——事实上恰恰相反。该程序是模块化的,用户可以在脚本中调整值并以新的行为运行程序,即使不需要重新编译或安装任何库。
  • 不,程序正在构建到单个文件中。但是,如果您要调整值,可能会将它们移到某种配置文件或命令行选项中?
  • 程序需要更多的可配置性,而不仅仅是几个选项。我需要动态执行代码。它适用于大多数事情,但如果我尝试动态导入所有内容,它会破坏多文件继承。如果我能得到一个运行 main.py 并且不编译任何 .py 文件的启动器,将它们作为 .py 文件而不是 .pyo 运行,它会完美运行。
  • 我明白了。请在下面尝试我的另一个解决方案。它生成带有 1 个源文件的应用程序文件夹。该文件在程序启动时被读取并执行。
猜你喜欢
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 2017-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多