# 28.4. `zipapp` - 管理可执行文件python zip档案

版本3.5中的新功能。

源代码： Lib / zipapp.py

此模块提供的工具可用于管理包含Python代码的zip文件的创建，这种zip文件可直接被Python解释器执行。该模块提供命令行界面和Python API。

## 28.4.1. Basic Example

以下示例说明如何从包含Python代码的目录使用命令行界面创建可执行文件。When run, the archive will execute the `main` function from the module `myapp` in the archive.

    $ python -m zipapp myapp -m "myapp:main"
    $ python myapp.pyz
    <output from myapp>

## 28.4.2. Command-Line Interface

当从命令行调用为程序时，使用以下形式：

    $ python -m zipapp source [options]

如果source是目录，则将从源的内容创建归档。如果source是一个文件，它应该是一个存档，并且它将被复制到目标存档（或者如果指定了-info选项，则将显示其shebang行的内容）。

以下选项被理解：

`-o``<output>``,` `--output``=<output>`

  将输出写入名为输出的文件。如果未指定此选项，则输出文件名将与输入源相同，并添加了扩展名`.pyz`。如果给定了显式文件名，则按原样使用（因此，如果需要，应包括`.pyz`扩展名）。

  如果源是存档（在这种情况下，输出不能与源相同），则必须指定输出文件名。

`-p``<interpreter>``,` `--python``=<interpreter>`

  添加`#!`行到指定解释器的档案作为要运行的命令。此外，在POSIX上，使归档可执行。默认值为不写`#!`行，并且不使文件可执行。

`-m``<mainfn>``,` `--main``=<mainfn>`

  将`__main__.py`文件写入执行mainfn的存档。mainfn参数的格式应为“pkg.mod：fn”，其中“pkg.mod”是存档中的包/模块，“fn”是给定模块中的可调用。`__main__.py`文件将执行该可调用。

  复制存档时无法指定`--main`。

`--info```

  显示嵌入在归档中的解释器，用于诊断目的。在这种情况下，将忽略任何其他选项，SOURCE必须是存档，而不是目录。

`-h````,` `--help```

  打印简短的使用消息并退出。

## 28.4.3. Python API

模块定义了两个方便的功能：

`zipapp.``create_archive`(source, target=None, interpreter=None, main=None)

  从源创建应用程序归档。源可以是以下任何一种：

  - 目录的名称或指向目录的`pathlib.Path`对象，在这种情况下，将从该目录的内容创建新的应用程序归档。
  - 现有应用程序归档文件的名称或引用此类文件的`pathlib.Path`对象，在这种情况下，将文件复制到目标（修改它以反映为>解释器参数）。如果需要，文件名应包含`.pyz`扩展名。
  - 以字节模式读取的文件对象。文件的内容应该是应用程序归档，并且文件对象假定位于归档的开始。

  目标参数确定将写入结果归档的位置：

  - 如果它是文件的名称或`pathlb.Path`对象，则归档将写入该文件。
  - 如果它是一个打开的文件对象，则归档将被写入该文件对象，该对象必须打开以便以字节模式写入。
  - 如果省略目标（或无），则源必须是目录，目标将是与源相同名称的文件，并添加了`.pyz`扩展名。

  解释器参数指定将要执行归档的Python解释器的名称。它在归档开始时写为“shebang”行。在POSIX上，这将被操作系统解释，在Windows上它将由Python启动程序处理。省略解释器会导致没有写入shebang行。如果指定了解释器，并且目标是文件名，则将设置目标文件的可执行位。

  main参数指定将用作归档的主程序的可调用的名称。它只能在源是目录且源尚未包含`__main__.py`文件时才能指定。main参数应采用“pkg.module：callable”的形式，并且通过导入“pkg.module”并执行没有参数的给定callable来运行归档。如果源是目录并且不包含`__main__.py`文件，则省略main是错误，否则生成的归档将不可执行。

  如果为source或target指定了文件对象，则调用create_archive后，调用者应负责关闭它。

  复制现有存档时，提供的文件对象只需要`read`和`readline`或`write`方法。从目录创建归档时，如果目标是文件对象，则它将传递到`zipfile.ZipFile`类，并且必须提供该类所需的方法。

`zipapp.``get_interpreter`(archive)

  返回`#!`中指定的解释器行在归档的开始。如果没有`#!`行，返回`None`。archive参数可以是以字节模式读取的文件名或类文件对象。它假定在​​归档的开始。

## 28.4.4. Examples

将目录封装到归档中，并运行它。

    $ python -m zipapp myapp
    $ python myapp.pyz
    <output from myapp>

同样可以使用`create_archive()` functon：

    >>> import zipapp
    >>> zipapp.create_archive('myapp.pyz', 'myapp')

要使应用程序在POSIX上可直接执行，请指定要使用的解释器。

    $ python -m zipapp myapp -p "/usr/bin/env python"
    $ ./myapp.pyz
    <output from myapp>

要替换现有归档上的shebang行，请使用`create_archive()`函数创建修改的归档：

    >>> import zipapp
    >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')

要立即更新文件，请使用`BytesIO`对象在内存中进行替换，然后再覆盖源。请注意，在覆盖文件时存在错误将导致原始文件丢失的风险。此代码不能防止此类错误，但生产代码应该这样做。此外，此方法将只有工作，如果存档适合内存：

    >>> import zipapp
    >>> import io
    >>> temp = io.BytesIO()
    >>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
    >>> with open('myapp.pyz', 'wb') as f:
    >>>     f.write(temp.getvalue())

请注意，如果指定解释器，然后分发应用程序归档，则需要确保使用的解释器是可移植的。Windows的Python启动器支持POSIX `#!`的最常见形式线，但还有其他问题需要考虑：

- 如果你使用“/ usr / bin / env python”（或其他形式的“python”命令，如“/ usr / bin / python”），你需要考虑你的用户可能有Python 2或Python 3作为它们的默认值，并且编写代码以在两个版本下工作。
- 如果您使用显式版本，例如“/ usr / bin / env python3”，您的应用程序将不适用于没有该版本的用户。（这可能是你想要的，如果你没有使你的代码Python 2兼容）。
- 没有办法说“python XY或更高版本”，所以要小心使用像“/ usr / bin / env python3.4”的确切版本，因为你需要为Python 3.5的用户更改你的shebang行，例如。

## 28.4.5. The Python Zip Application Archive Format

Python自2.6版本起就能够执行包含`__main__.py`文件的zip文件。为了由Python执行，应用程序归档只需要是包含`__main__.py`文件的标准zip文件，该文件将作为应用程序的入口点运行。与任何Python脚本一样，脚本的父代（在这种情况下为zip文件）将放置在`sys.path`上，因此可以从zip文件导入更多模块。

zip文件格式允许将任意数据添加到zip文件。zip应用程序格式使用此功能在文件（`#!/path/to/interpreter`）前面添加标准POSIX“shebang”行。

正式来说，Python zip应用程序格式是：

1. 可选的shebang行，包含字符`b'#!'`后跟解释器名称，然后是换行符（`b'\n'`）字符。解释器名称可以是OS“shebang”处理或Windows上的Python启动器可接受的任何名称。解释器应该在Windows上以UTF-8编码，在POSIX上在`sys.getfilesystemencoding()`中编码。
2. 标准zip文件数据，由`zipfile`模块生成。zip文件内容必须包含一个名为`__main__.py`的文件（它必须位于zip文件的“根目录”中，即不能位于子目录中）。zipfile数据可以是压缩的或未压缩的。

如果应用程序归档具有shebang行，则它可以在POSIX系统上设置可执行位，以允许它直接执行。

没有要求该模块中的工具用于创建应用程序存档 - 该模块是方便的，但是通过任何方式创建的上述格式的存档都可以被Python接受。