在Python编程世界中,随着项目规模的增长,代码的管理和组织变得至关重要。单个文件不足以应对复杂性,这时“包”(package)的概念应运而生,成为构建大型、可维护应用的基石。

python包是什么?

简单来说,一个Python包是一种组织Python模块(module)的方式。如果说模块是一个包含Python代码的单个文件(以.py为扩展名),那么包就是一个包含多个模块以及子包的目录。

判断一个目录是否被视为Python包的关键在于,它通常包含一个名为__init__.py的特殊文件(在Python 3.3及之后,即使没有__init__.py文件,包含模块的目录也可以被视为隐式命名空间包,但显式包仍然是主流且推荐的方式)。这个__init__.py文件可以是空的,也可以包含包级别的初始化代码,或者定义__all__变量来控制from package import *的行为。

因此,一个Python包的结构大致如下所示:

my_package/
├── __init__.py
├── module1.py
├── module2.py
└── sub_package/
    ├── __init__.py
    ├── module_a.py
    └── module_b.py

在这个例子中,my_package是一个包,它包含了两个模块(module1.pymodule2.py)以及一个子包(sub_package),而sub_package本身又包含了自己的模块(module_a.pymodule_b.py)。

为什么使用python包?

使用Python包带来了诸多显著优势,是构建任何非简单脚本项目的必要手段:

  1. 代码组织与模块化:将大型项目分解为逻辑上相关的、更小的模块和子包,使代码结构清晰,易于理解和管理。每个模块或子包可以专注于特定的功能。
  2. 避免命名冲突:不同的包可以拥有同名的模块或函数,通过包的层级结构(例如 my_package.module1another_package.module1)来区分,解决了全局命名空间的混乱问题。
  3. 代码复用性:通过将常用功能封装在模块和包中,可以在不同的项目或项目的不同部分导入和重复使用这些代码,提高了开发效率。
  4. 简化维护:当需要修改某个功能时,可以快速定位到对应的模块或包进行修改,而不会影响到项目的其他部分,降低了维护成本。
  5. 便于分发与共享:遵循标准的包结构后,可以轻松地将自己的代码打包成一个可分发的库,分享给其他开发者使用,或者发布到公共仓库(如 PyPI)。
  6. 促进协作:在团队开发中,不同的成员可以负责开发不同的包或模块,通过明确的接口进行集成,提高了团队协作效率。

如果没有包,所有代码都堆积在少数几个大文件中,这将导致代码臃肿、难以导航、依赖关系混乱,并且极易产生命名冲突,项目将难以扩展和维护。

python包在哪里?

Python包的“在哪里”可以从几个层面理解:

  1. 代码源:

    • Python标准库:Python安装时自带的包和模块,例如ossysmathjsondatetime等。这些包无需额外安装,可以直接导入使用。
    • 第三方库:由广大社区或公司开发的、非Python自带的包。绝大多数这类包都托管在Python Package Index (PyPI)上,这是Python官方的第三方软件包仓库。例如,requestsnumpypandasDjangoFlask等都来自于此。
    • 私有仓库:有些组织会搭建内部的PyPI镜像或使用Artifactory、Nexus等工具来存储和管理内部开发的私有包。
    • 本地文件或版本控制系统:可以直接从本地文件路径或通过版本控制系统(如 Git)仓库的URL安装包。
  2. 安装位置(物理存储):

    当使用工具(如pip)安装包时,它们通常会被放置在Python环境的site-packages目录下。这个目录是Python解释器查找第三方包的默认路径。

    理解 site-packages 与环境

    重要的是要理解包被安装在哪个Python环境中。为了避免不同项目之间依赖冲突,强烈推荐使用虚拟环境(Virtual Environments)

    • 虚拟环境:虚拟环境是一个独立的Python安装副本,它有自己的解释器、pip以及独立的site-packages目录。在一个虚拟环境中安装的包不会影响到系统全局的Python或其他虚拟环境。这是管理项目依赖的最佳实践。常见的虚拟环境工具有 Python 3.3+ 内置的 venv,以及第三方的 virtualenvconda 等。
    • 系统全局环境:如果不在虚拟环境中安装,包可能会被安装到系统全局的Python环境的site-packages目录。这可能导致不同项目共享同一套包,一旦某个项目需要特定版本的包,就可能与依赖其他版本的项目发生冲突。应尽量避免向全局环境安装包。

    当你在代码中写下import package_name时,Python解释器会按照一个特定的路径顺序(存储在sys.path列表中)去查找对应的包或模块文件。通常查找顺序包括:当前目录、PYTHONPATH环境变量指定的目录、以及Python环境的site-packages目录。

  3. 查找与发现:

    发现可用的第三方包主要通过访问PyPI官网进行搜索。你可以在这里找到各种功能的包,查看它们的描述、文档、版本信息、作者和许可证等。此外,许多包的开发托管在GitHub等平台上,你也可以直接在这些平台上搜索项目。

python包多少钱?

绝大多数托管在PyPI上的Python包都是免费且开源的。这意味着你可以免费获取、使用、修改和分发这些包的代码。这是Python社区强大和充满活力的重要原因之一。

虽然包本身通常是免费的,但你需要注意其许可证(License)。许可证规定了你使用该包代码的权利和限制。常见的开源许可证包括:

  • MIT License:非常宽松,允许几乎任何使用,包括商业用途,只需要保留原始版权和许可证信息。
  • Apache License 2.0:也比较宽松,允许商业使用,但有一些附加条款,例如需要包含通知文件和声明修改。
  • GPL (GNU General Public License):传染性许可证。如果你的项目使用了GPLv2或GPLv3许可的代码,你的整个项目(或者至少是与GPL代码交互的部分)也可能需要使用GPL许可证开源。
  • BSD License:类似于MIT,非常宽松。

在使用任何第三方包之前,查阅其许可证是一个良好的实践,以确保你的使用方式符合其规定,尤其是在商业项目中。

当然,也有一些商业闭源的Python库或服务,这些需要付费购买授权才能使用。但这在整个Python生态中占比较小,大量核心功能和常用工具都有高质量的开源替代品。

总的来说,获取和使用Python包的直接“金钱”成本通常是零,但理解并遵守其许可证是你的责任。

如何获取与管理python包?

获取和管理Python包主要依赖于包管理器,其中最常用的是pip

使用 pip

pip是Python的官方推荐包管理器,用于从PyPI或其他仓库安装、升级和卸载包。

安装 pip

现代的Python安装版本(Python 3.4+ 和 Python 2.7.9+)通常都自带了pip。你可以在命令行中运行以下命令检查是否已安装以及版本:

pip --version

或者在确保使用特定 Python 版本下的 pip 时:

python -m pip --version

如果未安装,可以从 pip 官方安装指南 获取安装脚本 get-pip.py 进行安装。

安装包

在命令行中执行安装命令:

pip install package_name

例如,安装流行的requests库:

pip install requests

你可以指定安装特定版本的包:

pip install package_name==1.2.3

安装满足某个版本范围的包:

pip install package_name>=1.2.0,<2.0.0

安装包的最新版本(如果已安装旧版本):

pip install --upgrade package_name

管理依赖:requirements.txt

在一个项目中,通常会依赖多个包。为了记录这些依赖及其版本,并方便在不同环境或设备上重现相同的环境,可以使用requirements.txt文件。

  • 生成依赖列表:在项目根目录下运行,可以将当前环境中由pip安装的所有包及其精确版本号输出到文件:
  •     

    pip freeze > requirements.txt

    生成的requirements.txt文件内容类似这样:

        requests==2.28.1
        idna==3.4
        charset-normalizer==2.1.1
        urllib3==1.26.12
        certifi==2022.9.24
        
  • 安装依赖:在新的环境或设备上,进入项目目录,激活虚拟环境后,运行以下命令即可安装requirements.txt中列出的所有包:
  •     

    pip install -r requirements.txt

卸载包

移除不再需要的包:

pip uninstall package_name

pip会提示你确认卸载,输入yyes即可。

列出已安装的包

查看当前Python环境中已安装的所有包及其版本:

pip list

pip freeze不同,pip list可能包含一些pip自身需要的包,且输出格式略有差异。pip freeze更适合用来生成requirements.txt

使用虚拟环境 (venv)

如前所述,虚拟环境是管理依赖的关键。以下是使用Python 3自带的venv模块创建和使用虚拟环境的基本步骤:

  1. 创建虚拟环境:在项目根目录下运行此命令。myenv是你给虚拟环境起的名字,可以换成其他名称(如.venv, env)。
  2.     

    python -m venv myenv

    这会在当前目录下创建一个名为myenv的文件夹,包含独立的Python环境。

  3. 激活虚拟环境:
    • 在 Windows 命令提示符或 PowerShell 中:
    •             

      .\myenv\Scripts\activate

    • 在 Linux 或 macOS 的 Bash/Zsh 中:
    •             

      source myenv/bin/activate

    激活后,命令行的提示符前会显示虚拟环境的名称(如 (myenv)),表示你现在处于隔离的环境中。此时使用pip安装的包都会安装到这个虚拟环境的site-packages目录。

  4. 在虚拟环境中工作:在激活的环境中,使用pip install安装项目所需的包,使用python运行脚本等。
  5. 退出虚拟环境:完成工作后,运行以下命令退出当前虚拟环境,回到系统全局环境:
  6.     

    deactivate

始终在虚拟环境中安装和管理项目依赖是一个非常重要的习惯。

怎样使用已安装的python包?

使用已安装的Python包非常简单,主要通过import语句在你的Python代码中引入包或其内部的模块和对象。

import 语句

import语句是Python中引入外部代码的标准方式。

  1. 导入整个包:
  2.     

    import package_name

    导入后,你可以通过package_name.前缀来访问包内的模块、函数、类等。例如,如果你安装了requests包:

        

    import requests

    response = requests.get('https://www.example.com')

    print(response.status_code)

  3. 导入包中的特定模块:
  4.     

    import package_name.module_name

    然后通过package_name.module_name.前缀访问模块内容。例如:

        

    import xml.etree.ElementTree

    tree = xml.etree.ElementTree.parse('myfile.xml')

  5. 从包中导入特定模块或对象:
  6.     

    from package_name import module_name

    from package_name.module_name import function_name, ClassName

    使用这种方式导入后,可以直接使用被导入的模块名或对象名,无需加上包或模块前缀(除非存在同名冲突)。

        

    from requests import get

    response = get('https://www.example.com') # 直接使用 get 函数


    from xml.etree import ElementTree

    tree = ElementTree.parse('myfile.xml') # 直接使用 ElementTree

  7. 使用别名(as):
  8. 为了简化名称或避免冲突,可以使用as关键字为导入的包、模块或对象设置别名:

        

    import package_name as pkg

    from package_name import module_name as mod

    from package_name.module_name import function_name as func

        

    import numpy as np

    data = np.array([1, 2, 3]) # 使用别名 np

  9. 警告:避免使用 from package import *

            

    from package_name import *

    这种方式会将包或模块中所有公开的名称(由__all__定义或以下划线开头的除外)导入到当前命名空间。虽然这看似方便,但强烈不推荐在实际代码中使用,因为它会污染当前命名空间,让你难以分辨一个函数或变量是来自哪个包,降低代码的可读性和维护性,并可能引入意外的命名冲突。

使用包的关键在于查阅其官方文档。文档会详细说明如何导入包,包中包含哪些模块、类、函数以及如何使用它们。

如何创建自己的python包?

创建自己的Python包并使其可安装和分发是一个非常有用的技能。以下是创建基本Python包的步骤概述:

  1. 组织目录结构:

    首先,创建一个主目录作为你的包的根目录,例如my_awesome_package/。在这个目录下,再创建一个与包同名的子目录,例如my_awesome_package/my_awesome_package/。所有实际的模块文件都放在这个内部的my_awesome_package/目录中。

    在这个内部目录中,创建__init__.py文件,以及你的模块文件(例如module1.py, utils.py等)。如果你的包包含子包,就在内部目录中创建子目录,并在每个子目录中也包含一个__init__.py文件。

    典型的结构:

            my_awesome_package/
            ├── my_awesome_package/
            │   ├── __init__.py
            │   ├── module1.py
            │   └── sub_package/
            │       ├── __init__.py
            │       └── sub_module_a.py
            └── (其他文件,如 setup.py 或 pyproject.toml, README.md, LICENSE)
            

    顶层目录my_awesome_package/是项目仓库的根目录,而内部的my_awesome_package/才是真正的包目录。

  2. 编写代码:

    在模块文件(如module1.py)中编写你的函数、类等代码。在__init__.py中,你可以导入包内部常用的对象,以便用户直接从包名访问,例如:

            

    # my_awesome_package/__init__.py

    from .module1 import my_function

    from .sub_package.sub_module_a import AnotherClass


    __version__ = "0.1.0"


    __all__ = ["my_function", "AnotherClass"] # 定义 * 导入时包含的对象

    这样用户就可以写 from my_awesome_package import my_functionimport my_awesome_package 然后使用 my_awesome_package.my_function()

  3. 创建打包元信息:

    需要一个文件来描述你的包的信息(名称、版本、作者、依赖等)以及如何构建它。传统上使用setup.pysetuptools库,现在更推荐使用pyproject.toml和构建工具(如build)。

    使用 pyproject.toml (推荐)

    在项目根目录 (my_awesome_package/) 创建pyproject.toml文件:

            

    # pyproject.toml

    [build-system]

    requires = ["setuptools>=61.0"]

    build-backend = "setuptools.build_meta"


    [project]

    name = "my-awesome-package" # 包的名称,在 PyPI 上是唯一的

    version = "0.1.0"

    authors = [

    { name="Your Name", email="[email protected]" },

    ]

    description = "A short description of my awesome package."

    readme = "README.md"

    requires-python = ">=3.7" # 最低 Python 版本要求

    classifiers = [ # 包的分类信息,有助于搜索

    "Programming Language :: Python :: 3",

    "License :: OSI Approved :: MIT License", # 你的许可证

    "Operating System :: OS Independent",

    ]


    [project.urls] # 可选:项目相关的链接

    "Homepage" = "https://github.com/yourusername/my-awesome-package"

    "Bug Tracker" = "https://github.com/yourusername/my-awesome-package/issues"


    [project.dependencies] # 项目运行时依赖的包

    requests = ">=2.20"

    numpy = ">=1.18"


    [project.optional-dependencies] # 可选依赖,例如用于测试或文档

    dev = ["pytest>=7.0", "build>=0.5.0", "twine>=4.0.0"]

    确保你有README.mdLICENSE文件在项目根目录。

  4. 构建分发包:

    安装构建工具(如果你在pyproject.toml的dev依赖中列出了):

            

    pip install build twine

    在项目根目录运行构建命令:

            

    python -m build

    这会在项目根目录创建一个dist/子目录,其中包含源分发包(.tar.gz)和轮子包(.whl)。

  5. 本地安装测试:

    可以在另一个环境中或在当前虚拟环境中测试安装你刚刚构建的包:

            

    pip install ./dist/my_awesome_package-0.1.0-py3-none-any.whl

    或者使用源代码安装:

    pip install ./dist/my_awesome_package-0.1.0.tar.gz

    为了方便开发过程中的修改和测试,可以使用可编辑安装:

    pip install -e .

    在项目根目录运行此命令,它会安装一个指向你本地代码的链接,修改代码后无需重新安装即可看到效果。

  6. 分发到 PyPI (可选):

    如果你想将包分享给社区,可以将其上传到 PyPI。首先需要在 PyPI (生产环境) 和 TestPyPI (测试环境) 注册账号并获取 API 令牌。

    使用twine工具上传:

            

    twine upload dist/* # 上传到生产环境 PyPI

    twine upload --repository testpypi dist/* # 上传到测试环境 TestPyPI

    上传后,其他人就可以使用pip install my-awesome-package来安装你的包了(如果上传到生产环境)。

创建高质量的包还需要编写文档、添加测试用例、选择合适的许可证等,这些都是包开发的重要组成部分,但上述步骤提供了创建和分发一个基本Python包的核心流程。

Python包是构建任何非trivial项目的核心组织单元。理解它们的结构、作用、获取方式、管理方法以及如何使用,是成为一名高效Python开发者的必备技能。通过合理地使用和创建包,可以极大地提升代码的质量、可维护性和复用性。