geekdoc-python-zh/docs/pythonlibrary/python-101-how-to-create-a-...

16 KiB
Raw Permalink Blame History

Python 101 -如何创建 Python 包

原文:https://www.blog.pythonlibrary.org/2021/09/23/python-101-how-to-create-a-python-package/

当您创建一个 Python 文件时,您正在创建一个 Python 模块。您创建的任何 Python 文件都可以由另一个 Python 脚本导入。因此,根据定义,它也是一个 Python 模块。如果您有两个或更多相关的 Python 文件,那么您可能有一个 Python 包。

一些组织将他们所有的代码留给自己。这就是所谓的闭源。Python 是一种开源语言,你可以从 Python 包索引(PyPI) 获得的大部分 Python 模块和包也都是免费和开源的。共享您的包或模块的最快方法之一是将它上传到 Python 包索引或 Github 或两者。

在本文中,您将了解以下主题:

  • 创建模块
  • 创建包
  • 为 PyPI 打包项目
  • 创建项目文件
  • 正在创建setup.py
  • 上传到 PyPI

这个过程的第一步是理解创建一个可重用模块是什么样子的。我们开始吧!

创建模块

您创建的任何 Python 文件都是可以导入的模块。您可以通过向任何文章的代码文件夹中添加一个新文件,并尝试在其中导入一个模块,用本书中的一些示例来尝试一下。例如,如果您有一个名为a.py的 Python 文件,然后创建一个名为b.py的新文件,您可以通过使用import aa导入到b中。

当然,这是一个愚蠢的例子。相反,您将创建一个简单的模块,其中包含一些基本的算术函数。您可以将文件命名为arithmetic.py,并将以下代码添加到其中:

# arithmetic.py

def add(x, y):
    return x + y

def divide(x, y):
    return x / y

def multiply(x, y):
    return x * y

def subtract(x, y):
    return x - y

这段代码很幼稚。例如,您根本没有错误处理。这意味着你可以除以零,并引发一个异常。您还可以向这些函数传递不兼容的类型,比如字符串和整数——这将导致引发不同类型的异常。

但是,出于学习的目的,这段代码已经足够了。您可以通过创建一个测试文件来证明它是可导入的。创建一个名为test_arithmetic.py的新文件,并将以下代码添加到其中:

# test_arithmetic.py

import arithmetic
import unittest

class TestArithmetic(unittest.TestCase):

    def test_addition(self):
        self.assertEqual(arithmetic.add(1, 2), 3)

    def test_subtraction(self):
        self.assertEqual(arithmetic.subtract(2, 1), 1)

    def test_multiplication(self):
        self.assertEqual(arithmetic.multiply(5, 5), 25)

    def test_division(self):
        self.assertEqual(arithmetic.divide(8, 2), 4)

if __name__ == '__main__':
    unittest.main()

将测试保存在与模块相同的文件夹中。现在,您可以使用以下命令运行这段代码:

$ python3 test_arithmetic.py 
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

这表明您可以将arithmetic.py作为一个模块导入。这些测试还显示了代码工作的基本功能。您可以通过测试被零除以及混合字符串和整数来增强这些测试。这些类型的测试目前会失败。一旦您有一个失败的测试,您可以遵循测试驱动的开发方法来修复问题。

现在让我们来看看如何制作一个 Python 包!

创建包

Python 包是您计划与其他人共享的一个或多个文件,通常通过将其上传到 Python 包索引(PyPI)来实现。包通常是通过命名文件目录而不是文件本身来制作的。然后,在该目录中,您将有一个特殊的__init__.py文件。当 Python 看到__init__.py文件时,它知道这个文件夹可以作为一个包导入。

有几种方法可以将arithmetic.py转换成一个包。最简单的方法是将代码从arithmetic.py移到arithmetic/__init__.py:

  • 创建文件夹arithmetic
  • arithmetic.py移动/复制到arithmetic/__init__.py
  • 如果在上一步中使用了“复制”,则删除arithmetic.py
  • 运行test_arithmetic.py

最后一步非常重要!如果您的测试仍然通过,那么您就知道从模块到包的转换成功了。要测试你的包,如果你在 Windows 上打开一个命令提示符,如果你在 Mac 或 Linux 上打开一个终端。然后导航到包含arithmetic文件夹的文件夹,但不在其中。现在你应该和你的test_arithmetic.py文件在同一个文件夹中。此时你可以运行python test_arithmetic.py,看看你的努力是否成功。

简单地将所有代码放在一个__init__.py文件中似乎很愚蠢,但是对于长达几千行的文件来说,这确实很好。

arithmetic.py转换成一个包的第二种方式与第一种类似,但是涉及到使用比__init__.py更多的文件。在实代码中,函数/类等。在中,每个文件都会以某种方式分组——可能一个文件用于所有的定制异常,一个文件用于公共工具,一个文件用于主要功能。

对于我们的例子,您只需将arithmetic.py中的四个函数拆分到它们自己的文件中。继续将每个函数从__init__.py移到它自己的文件中。您的文件夹结构应该如下所示:

arithmetic/
    __init__.py
    add.py
    subtract.py
    multiply.py
    divide.py

对于__init__.py文件,您可以添加以下代码:

# __init__.py
from .add import add
from .subtract import subtract
from .multiply import multiply
from .divide import divide

现在你已经做了这些改变,你的下一步应该是什么?希望你说,“运行我的测试!”如果您的测试仍然通过,那么您没有破坏您的 API。

现在,如果你碰巧和你的test_arithmetic.py文件在同一个文件夹中,你的arithmetic包只对你的其他 Python 代码可用。要使它在 Python 会话或其他 Python 代码中可用,您可以使用 Python 的sys模块将您的包添加到 Python 搜索路径。当您使用import关键字时Python 使用搜索路径来查找模块。通过打印出sys.path,你可以看到 Python 搜索了哪些路径。

假设你的arithmetic文件夹在这个位置:/Users/michael/packages/arithmetic。要将它添加到 Python 的搜索路径中,您可以这样做:

import sys

sys.path.append("/Users/michael/packages/arithmetic")
import arithmetic

print(arithmetic.add(1, 2))

这将把arithmetic添加到 Python 的路径中,这样你就可以导入它,然后在你的代码中使用这个包。然而,那真的很尴尬。如果你能使用pip来安装你的软件包就好了,这样你就不用一直摆弄路径了。

让我们看看接下来该怎么做!

为 PyPI 打包项目

在为 Python 包索引(PyPI)创建包时,您将需要一些附加文件。这里有一个很好的教程,介绍了创建包并上传到 PyPI 的过程:

官方包装说明建议您建立如下目录结构:

my_package/
    LICENSE
    README.md
    arithmetic/
        __init__.py
        add.py
        subtract.py
        multiply.py
        divide.py
    setup.py
    tests/

tests文件夹可以是空的。这是您将包含包测试的文件夹。大多数开发人员使用 Python 的unittestpytest框架进行测试。对于本例,您可以将文件夹留空。

让我们继续,在下一节中学习您需要创建的其他文件!

创建项目文件

许可证文件中您可以提到您的软件包拥有什么许可证。这告诉软件包的用户他们能做什么不能做什么。您可以使用许多不同的许可证。GPL 和 MIT 许可证只是两个流行的例子。

README.md 文件是对你的项目的描述,用 Markdown 编写。您将希望在这个文件中写下您的项目并包括它可能需要的关于依赖项的任何信息。您可以给出安装说明以及软件包的示例用法。Markdown 是相当多才多艺的,甚至让你做语法突出!

你需要提供的另一个文件是setup.py。该文件更复杂,因此您将在下一节中了解这一点。

正在创建setup.py

有一个名为setup.py的特殊文件,用作 Python 发行版的构建脚本。它由setuptools使用,它为您进行实际的构建。如果你想了解更多关于setuptools的信息,那么你应该看看以下内容:

你可以使用setup.py来创建一个 Python 轮子。wheel 是一个 ZIP 格式的存档文件,有一个特殊格式的名称和一个.whl扩展名。它包含安装软件包所需的一切。你可以把它想象成你的代码的压缩版本,pip可以帮你解压并安装。车轮遵循 PEP 376您可以在这里阅读:

一旦你读完了所有的文档(如果你想的话),你就可以创建你的setup.py并把这段代码添加进去:

import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="arithmetic-YOUR-USERNAME-HERE", # Replace with your own username
    version="0.0.1",
    author="Mike Driscoll",
    author_email="driscoll@example.com",
    description="A simple arithmetic package",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/driscollis/arithmetic",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',
)

这段代码的第一步是导入setuptools。然后,将您的README.md文件读入一个您很快就会用到的变量。最后一位是大部分代码。这里你调用setuptools.setup(),它可以接受很多不同的参数。上面的例子只是你可以传递给这个函数的一个例子。要查看完整列表,您需要访问此处:

大多数论点都是不言自明的。让我们把注意力集中在更迟钝的人身上。packages参数是您的包所需的包的列表。在这种情况下,您使用find_packages()自动为您找到必要的包。classifiers参数用于向pip传递额外的元数据。例如,这段代码告诉pip这个包是 Python 3 兼容的。

现在你已经有了一个setup.py,你已经准备好创建一个 Python 轮子了!

生成 Python 轮子

setup.py用于创建 Python 轮子。确保你已经安装了最新版本的setuptoolswheel总是一个好主意,所以在你创建你自己的轮子之前,你应该运行下面的命令:

python3 -m pip install --user --upgrade setuptools wheel

如果有比您当前安装的版本更新的版本,这将更新软件包。现在你已经准备好自己创建一个轮子了。打开命令提示符或终端应用程序,导航到包含您的setup.py文件的文件夹。然后运行以下命令:

python3 setup.py sdist bdist_wheel

该命令将输出大量文本,但一旦完成,您会发现一个名为dist的新文件夹,其中包含以下两个文件:

  • arithmetic_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
  • arithmetic-YOUR-USERNAME-HERE-0.0.1.tar.gz

tar.gz是一个源文件,这意味着它包含了您的包的 Python 源代码。如果需要,您的用户可以使用源归档文件在他们自己的机器上构建包。whl格式是一个归档文件,由pip用来在用户的机器上安装你的软件包。

如果需要,您可以使用pip直接安装车轮:

python3 -m pip install arithmetic_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl

但是通常的方法是将您的包上传到 Python 包索引(PyPI ),然后安装它。接下来,让我们来看看如何在 PyPI 上获得您的惊喜套餐吧!

上传到 PyPI

将包上传到 PyPI 的第一步是在 Test PyPI 上创建一个帐户。这允许您测试您的包是否可以上传到测试服务器上,并从该测试服务器安装。要创建帐户,请转到以下 URL 并按照该页面上的步骤操作:

现在您需要创建一个 PyPI API 令牌。这将允许您安全地上传软件包。要获得 API 令牌,您需要转到这里:

您可以限制令牌的范围。但是,您不需要为这个令牌这样做,因为您正在为一个新项目创建它。确保在关闭页面之前复制令牌并将其保存在某个地方。一旦页面关闭,您将无法再次检索令牌。您将需要创建一个新的令牌。

现在您已经注册并拥有了 API 令牌,您将需要获得twine包。您将使用twine将您的包上传到 PyPI。要安装twine,可以这样使用pip:

python3 -m pip install --user --upgrade twine

安装完成后,您可以使用以下命令将您的包上传到测试 PyPI:

python3 -m twine upload --repository testpypi dist/*

注意,您需要从包含setup.py文件的文件夹中运行这个命令,因为它正在复制dist文件夹中的所有文件来测试 PyPI。当您运行这个命令时它会提示您输入用户名和密码。对于用户名您需要使用__token__。密码是以pypi-为前缀的令牌值。

当此命令运行时,您应该会看到类似如下的输出:

Uploading distributions to https://test.pypi.org/legacy/
Enter your username: [your username]
Enter your password:
Uploading arithmetic_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
100%|?????????????????????| 4.65k/4.65k [00:01<00:00, 2.88kB/s]
Uploading arithmetic_YOUR_USERNAME_HERE-0.0.1.tar.gz
100%|?????????????????????| 4.25k/4.25k [00:01<00:00, 3.05kB/s]

至此,您应该能够在 Test PyPI 上查看您的包,网址如下:

现在您可以使用下面的命令从 Test PyPI 测试安装您的包:

python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps arithmetic-YOUR-USERNAME-HERE

如果一切正常,您现在应该已经在系统上安装了arithmetic包。当然,本教程向您展示了如何打包测试 PyPI。一旦您验证了它可以工作那么您将需要执行以下操作来安装到真正的 PyPI:

  • 为包装选择一个容易记忆且独特的名称
  • https://pypi.org注册账户
  • 使用twine upload dist/*上传您的包裹,并输入您在 real PyPI 上注册的帐户的凭证。当上传到真正的 PyPI 时,您不需要使用--repository标志,因为该服务器是默认的
  • 使用pip install your_unique_package_name从真实的 PyPI 安装你的包

现在您知道如何在 Python 包索引上分发您自己创建的包了!

包扎

Python 模块和包是您在程序中导入的内容。从很多方面来说,它们是你的程序的组成部分。在本文中,您了解了以下内容:

  • 创建模块
  • 创建包
  • 为 PyPI 打包项目
  • 创建项目文件
  • 正在创建setup.py
  • 上传到 PyPI

至此,您不仅知道了什么是模块和包,还知道了如何通过 Python 包索引来分发它们。现在,您和任何其他 Python 开发人员都可以下载并安装您的包。恭喜你!你现在是一个包维护者了!

相关阅读

这篇文章基于 Python 101 第二版中的一章,你可以在 Leanpub亚马逊上购买。

如果你想学习更多的 Python那么看看这些教程: