【问题标题】:How to build a single python file from multiple scripts?如何从多个脚本构建单个 python 文件?
【发布时间】:2012-02-18 14:40:10
【问题描述】:

我有一个简单的 python 脚本,它可以导入我编写的各种其他模块(等等)。由于我的环境,我的 PYTHONPATH 很长。我也在使用 Python 2.4。

我需要做的是以某种方式打包我的脚本和所有不属于标准 python 的依赖项,以便我可以将单个文件通过电子邮件发送到另一个我想要执行它的系统。我知道 python 的目标版本是相同的,但它在我在 Windows 上的 linux 上。否则我只会使用 py2exe。

理想情况下,我想发送一个 .py 文件,该文件以某种方式嵌入了所有必需的模块,但我会满足于自动构建一个我可以解压缩的 zip,所需的模块都在一个目录中。

我查看了各种包装解决方案,但似乎找不到合适的方法。我错过了什么吗?

[edit] 我似乎很不清楚我在追求什么。我基本上是在寻找类似 py2exe 的东西,它会从给定的 python 脚本中生成一个文件(或两个文件),自动包含所有导入的模块。

例如,如果我有以下两个文件:

[\foo\module.py]
def example():
    print "Hello"

[\bar\program.py]
import module
module.example()

然后我跑:

cd \bar
set PYTHONPATH=\foo
program.py

然后它将起作用。我想要的是能够说:

magic program.py

最后得到一个文件,或者可能是一个文件和一个 zip,然后我可以将其复制到 linux 并运行。我不想在目标 linux 系统上安装我的模块。

【问题讨论】:

标签: python


【解决方案1】:

使用stickytape 模块

stickytape scripts/blah --add-python-path . > /tmp/blah-standalone

这将产生一个正常运行的脚本,但不一定是人类可读的。

【讨论】:

  • 我希望我的 Python 脚本的连接是可读的,但对我来说,它生成了充满特殊粘性调用的不可读代码。
  • @CGFoX 感谢您发现这一点,我更新了响应文本以反映这一点,以便为寻找人类可读输出的人们节省时间。
【解决方案2】:

您应该创建一个 egg 文件。这是 python 文件的存档。

请参阅此问题以获得指导:How to create Python egg file

更新:考虑 2019 年的车轮

【讨论】:

  • 我不需要一个包吗?
  • @xorsyst: (1) 你的开发设置应该与你的部署设置完全分开,所以你实际上可以随意组织你的代码 (2) 一旦你有了你的鸡蛋,它就是一个文件。如果您可以将两个文件放在某处,则可以将一个文件放在那里 (3) 您似乎通过提出新要求来积极地贬低可行的解决方案。这至少可以说是不礼貌的。
  • 1:我的开发设置与我的部署设置是分开的。这是我的开发设置受到限制。 2:我吃鸡蛋没有问题。 3:我不是抛出新的要求,只是澄清原来的措辞不好的要求
  • @xorsyst:你不能在你的开发环境中创建目录?抱怨这妨碍了你有效地工作。
  • 我可以创建目录来存储文件的临时副本,但我不能做的是对我们的代码库进行全面重组,以使这项特定任务更容易。
【解决方案3】:

我发现这很有用:

http://blog.ablepear.com/2012/10/bundling-python-files-into-stand-alone.html

简而言之,您可以对模块进行 .zip 压缩并在其中包含一个 __main__.py 文件,这样您就可以像这样运行它:

python3 app.zip

由于我的应用很小,我从我的主脚本创建了一个链接到 __main__.py

附录:

您还可以通过在文件顶部添加一行来使 zip 在类 UNIX 系统上自执行。这对于使用 Python3 的脚本可能很重要。

echo '#!/usr/bin/env python3' | cat - app.zip > app
chmod a+x app

现在可以在不指定 python 的情况下执行

./app

【讨论】:

    【解决方案4】:

    您可以尝试将脚本转换为可执行文件。 一、使用:

    pip install pyinstaller

    安装后类型(确保你在你感兴趣的文件目录中):

    pyinstaller --onefile --windowed 文件名.py

    这将创建一个包含所有必要模块的脚本的可执行版本。然后,您可以将此可执行文件传输(复制和粘贴)到要运行脚本的 PC 或机器上。

    我希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      我提出了一个解决方案,涉及模块查找器、编译器和运行良好的 zip 函数。不幸的是,我无法在此处粘贴工作程序,因为它与其他不相关的代码混合在一起,但这里有一些 sn-ps:

      zipfile = ZipFile(os.path.join(dest_dir, zip_name), 'w', ZIP_DEFLATED)
      sys.path.insert(0, '.')
      finder = ModuleFinder()
      finder.run_script(source_name)
      
      for name, mod in finder.modules.iteritems():
          filename = mod.__file__
          if filename is None:
              continue
          if "python" in filename.lower():
              continue
      
          subprocess.call('"%s" -OO -m py_compile "%s"' % (python_exe, filename))
      
          zipfile.write(filename, dest_path)
      

      【讨论】:

        【解决方案6】:

        如果您想将脚本及其所有依赖项打包到一个文件中(它不会是 .py 文件),您应该查看virtualenv。这是一个工具,可让您构建沙箱环境以将 Python 包安装到其中,并管理所有 PATH、PYTHONPATH 和 LD_LIBRARY_PATH 问题,以确保沙箱完全独立。

        如果您从没有安装额外库的原始 Python 开始,然后将 easy_install 您的依赖项添加到虚拟环境中,您最终将在 virtualenv 中构建一个只需要运行 Python 的项目。

        沙盒是一个目录树,不是单个文件,但为了分发,您可以对其进行 tar/zip 压缩。我从未尝试过分发环境,所以可能存在路径依赖关系,我不确定。

        相反,您可能需要分发一个在目标机器上构建虚拟环境的构建脚本。 zc.buildout 是一个帮助自动化该过程的工具,有点像与 Python 包系统和 PyPI 紧密集成的“make install”。

        【讨论】:

        • 你应该使用 pip 和 virtualenv 而不是 easy_install
        • 有趣的模块——但我不认为我可以用它在 Windows 上创建环境然后将其移植到 Linux
        • 不,绝对不是。您也许可以制作一个自动创建和填充虚拟环境的构建脚本。
        【解决方案7】:

        您是否考虑过Automatic script creation 分发官方打包解决方案。

        您所做的是create a setup.py 为您编程并提供入口点,这些入口点将转换为您可以运行的可执行文件。这样您就不必更改源代码布局,同时仍然可以轻松分发和运行您的程序。

        你会在gunicorn's setup.py找到一个关于这个系统的真实应用程序的例子

        【讨论】:

        • 听起来很有趣,但是当我尝试给出的示例时,它不起作用。你能提供一个如何使用它的例子吗?
        • @xorsyst 我在答案中添加了一个示例。
        • 谢谢。我试过这个,但它似乎没有用。它构建了一个包含我当前目录中所有内容的 zip,并且不包含我导入的模块。我用错了吗?
        • 对不起,我没听懂你的问题。
        【解决方案8】:

        发送单个 .py 的唯一方法是将所有不同模块的代码移到单个脚本中,并且您必须重做所有操作以引用新位置。

        更好的方法是将相关模块移动到与您的命令相同的目录下的子目录中。然后,您可以确保包含该模块的子目录具有导入主模块文件的__init__.py。那时您可以通过它引用事物。

        例如:

        应用目录:/test

        模块目录:/test/hello

        /test/hello/__init__.py 内容:

        import sayhello
        

        /test/hello/sayhello.py 内容:

        def print_hello():
            print 'hello!'
        

        /test/test.py内容:

        #!/usr/bin/python2.7
        
        import hello
        
        hello.sayhello.print_hello()
        

        如果您运行/test/test.py,您将看到它从现有目录下的模块目录运行 print_hello 函数,无需更改您的PYTHONPATH

        【讨论】:

        • 很遗憾,无法移动源文件。
        • 我有点困惑。现在,您在顶部的问题中与您之前的陈述相矛盾。您说您想将所有内容移动到单个目录/文件中。如果您无法移动任何有问题的模块,那么由于您自己的内部政策,您甚至无法按照您的要求进行操作,所有技术限制除外。
        • 很抱歉给您带来了困惑。我无法在我的系统上永久移动文件。我想要做的是将所有必要的源文件收集到一个文件中,我可以将其放在目标系统上以运行 python。我不想在那里安装库。基本上,我正在寻找 py2exe,但这会产生一个基于源代码的跨平台存档。
        猜你喜欢
        • 1970-01-01
        • 2020-01-26
        • 2017-02-11
        • 2016-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-08
        相关资源
        最近更新 更多