将python脚本仅作为可执行文件发送

时间:2017-04-04 21:58:27

标签: python python-3.x scripting

我刚写了一个python脚本,我想将它发送给朋友,以便他们可以使用它。而不是仅仅向他们发送整个文本文件并教他们如何运行它(并反过来让他们访问源代码),我想知道如何将它打包成一个"程序"他们可以随时随地运行,无需访问代码本身。

更好的是,我应该寻找什么?关于如何做到这一点的说明会有所帮助,但我也想知道我究竟可以搜索什么来获得更多相关信息。

此外,这将是从unix机器到unix机器。

1 个答案:

答案 0 :(得分:1)

Python支持可执行档案。这是一种将程序和一堆模块包装到一个文件中的方法。例如,youtube-dl就像这样分发。

请注意"可执行文件"基本上只是一个前面有#!行的zip文件。因此,知识渊博的人仍然可以获得源代码。

在UNIX上,可以使用Makefilezip中轻松完成此操作。 但在某些平台上,这并不容易。所以我构建了一个名为build.py的纯Python解决方案。

"""Create runnable archives from program files and custom modules."""

import os
import py_compile
import tempfile
import zipfile as z


def mkarchive(name, modules, main='__main__.py',
              shebang=b'#!/usr/bin/env python3\n'):
    """Create a runnable archive.

    Arguments:
        name: Name of the archive.
        modules: Module name or iterable of module names to include.
        main: Name of the main file. Defaults to __main__.py
        shebang: Description of the interpreter to use. Defaults to Python 3.
    """
    std = '__main__.py'
    if isinstance(modules, str):
        modules = [modules]
    if main != std:
        try:
            os.remove(std)
        except OSError:
            pass
        os.link(main, std)
    # Forcibly compile __main__.py lest we use an old version!
    py_compile.compile(std)
    tmpf = tempfile.TemporaryFile()
    with z.PyZipFile(tmpf, mode='w', compression=z.ZIP_DEFLATED) as zf:
        zf.writepy(std)
        for m in modules:
            zf.writepy(m)
    if main != std:
        os.remove(std)
    tmpf.seek(0)
    archive_data = tmpf.read()
    tmpf.close()
    with open(name, 'wb') as archive:
        archive.write(shebang)
        archive.write(archive_data)
    os.chmod(name, 0o755)


if __name__ == '__main__':
    pass

这不应该是未经修改的。

build.py复制到您的项目中。然后根据下面给出的示例自定义in __name__ == '__main__' 之后的部分。

假设目录src包含多个Python文件,eggs.pyham.pyfoo.py。它还包含一个子目录spam,其中包含所有脚本使用的Python模块。以下代码将创建三个可执行存档eggshamfoo

if __name__ == '__main__':
    from shutil import copy
    os.chdir('src')
    programs = [f for f in os.listdir('.') if f.endswith('.py')]
    for pyfile in programs:
        name = pyfile[:-3]
        mkarchive(name, 'spam', pyfile)
        copy(name, '../'+name)
        os.remove(name)

如果您只想使用单个文件:

if __name__ == '__main__':
    mkarchive('scriptname', None, 'filename.py')