百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Python 命名空间包(python命名文件)

itomcoil 2025-03-19 13:36 14 浏览

在 Python 中,用包来组织模块。

Python 包

两种类型的包:

  1. 常规包
  2. 命名空间包

常规包

常规包是包含 __init__.py 文件的目录。此文件指示应将目录视为包。__init__.py 文件可以为空,但它通常用于初始化包、定义向外部公开的内容或在导入包时运行设置代码。

mypackage/
    __init__.py
    module1.py
    module2.py

命名空间包

命名空间包是一种类似包的结构,不需要 __init__.py 文件,并且可以跨越多个目录。它允许分布式和灵活的包创建,从而可以将包的不同部分拆分到不同的位置。

例:

想象一下分布在两个目录中的命名空间包 mynamespace

目录 1:

project1/mynamespace/
    module1.py

目录 2:

project2/mynamespace/
    module2.py

用法

import mynamespace.module1
import mynamespace.module2

Python 会将两个 mynamespace 目录合并到一个命名空间包中,使所有模块都可以访问。

比较

命名空间包示例

我们了解到 Namespace 包的源代码可以分布在多个目录中。它有助于根据团队对大型项目进行解耦,以便可以独立开发和分发包的组件。

例如:一个存储库(一个团队)可以处理一个组件,另一个团队可以处理同一包的另一个组件,但独立开发和分发。

让我们了解 Namespace 包如何帮助独立开发和分发包。

假设我们有一个公司 (log-corp) 提供了一个大而有用的包。但是该包的子包/模块在不同的存储库(目录)中是多样化的,因为不同的团队正在处理它。

  • log_corp 是主包,其中包含许多跨团队开发并独立分发的子包和模块。
  • 版本控制和包分发将独立进行。
  • 他们唯一共享的是命名空间。(所有子包和模块都将归入主包log_corp

团队 1(存储库 1)

使用 src 布局。

LOG_CORP_COMP1/
├── src/
│   └── log_corp/
│       ├── sub_pkg1/
│       │   └── sub_module1.py
│       └── module1.py
├── pyproject.toml
└── README.md

module1.py

def func1():
    print('From log-corp module1')

sub_module1.py

def sub_func1():
    print('From log-corp submodule1')

pyproject.toml 文件

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "log-corp1"  # as if it appears in pypi
authors = [
    {name = "Logesh", email = "log@gmail.com"},
]
description = "My package description"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT License"}
classifiers = [
    "Programming Language :: Python :: 3",
]
version = "1.0.1"   # version 1.0.1

构建软件包

PS C:\Users\L\Desktop\log_corp_comp1> ls


    Directory: C:\Users\L\Desktop\log_corp_comp1


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        12/28/2024  11:32 AM                src
-a----        12/28/2024  11:41 AM            387 pyproject.toml
-a----        12/28/2024  11:31 AM             34 README.md


PS C:\Users\L\Desktop\log_corp_comp1> python -m build
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for sdist...
running egg_info
creating src\log_corp1.egg-info
writing src\log_corp1.egg-info\PKG-INFO
writing dependency_links to src\log_corp1.egg-info\dependency_links.txt
writing top-level names to src\log_corp1.egg-info\top_level.txt
writing manifest file 'src\log_corp1.egg-info\SOURCES.txt'
reading manifest file 'src\log_corp1.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp1.egg-info\SOURCES.txt'
* Building sdist...
running sdist
running egg_info
writing src\log_corp1.egg-info\PKG-INFO
writing dependency_links to src\log_corp1.egg-info\dependency_links.txt
writing top-level names to src\log_corp1.egg-info\top_level.txt
reading manifest file 'src\log_corp1.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp1.egg-info\SOURCES.txt'
running check
creating log_corp1-1.0.1
creating log_corp1-1.0.1\src\log_corp
creating log_corp1-1.0.1\src\log_corp1.egg-info
creating log_corp1-1.0.1\src\log_corp\sub_pkg1
copying files to log_corp1-1.0.1...
copying README.md -> log_corp1-1.0.1
copying pyproject.toml -> log_corp1-1.0.1
copying src\log_corp\module1.py -> log_corp1-1.0.1\src\log_corp
copying src\log_corp1.egg-info\PKG-INFO -> log_corp1-1.0.1\src\log_corp1.egg-info
copying src\log_corp1.egg-info\SOURCES.txt -> log_corp1-1.0.1\src\log_corp1.egg-info
copying src\log_corp1.egg-info\dependency_links.txt -> log_corp1-1.0.1\src\log_corp1.egg-info
copying src\log_corp1.egg-info\top_level.txt -> log_corp1-1.0.1\src\log_corp1.egg-info
copying src\log_corp\sub_pkg1\sub_module1.py -> log_corp1-1.0.1\src\log_corp\sub_pkg1
copying src\log_corp1.egg-info\SOURCES.txt -> log_corp1-1.0.1\src\log_corp1.egg-info
Writing log_corp1-1.0.1\setup.cfg
Creating tar archive
removing 'log_corp1-1.0.1' (and everything under it)
* Building wheel from sdist
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for wheel...
running egg_info
writing src\log_corp1.egg-info\PKG-INFO
writing dependency_links to src\log_corp1.egg-info\dependency_links.txt
writing top-level names to src\log_corp1.egg-info\top_level.txt
reading manifest file 'src\log_corp1.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp1.egg-info\SOURCES.txt'
* Building wheel...
running bdist_wheel
running build
running build_py
creating build\lib\log_corp
copying src\log_corp\module1.py -> build\lib\log_corp
creating build\lib\log_corp\sub_pkg1
copying src\log_corp\sub_pkg1\sub_module1.py -> build\lib\log_corp\sub_pkg1
running egg_info
writing src\log_corp1.egg-info\PKG-INFO
writing dependency_links to src\log_corp1.egg-info\dependency_links.txt
writing top-level names to src\log_corp1.egg-info\top_level.txt
reading manifest file 'src\log_corp1.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp1.egg-info\SOURCES.txt'
installing to build\bdist.win-amd64\wheel
running install
running install_lib
creating build\bdist.win-amd64\wheel
creating build\bdist.win-amd64\wheel\log_corp
copying build\lib\log_corp\module1.py -> build\bdist.win-amd64\wheel\.\log_corp
creating build\bdist.win-amd64\wheel\log_corp\sub_pkg1
copying build\lib\log_corp\sub_pkg1\sub_module1.py -> build\bdist.win-amd64\wheel\.\log_corp\sub_pkg1
running install_egg_info
Copying src\log_corp1.egg-info to build\bdist.win-amd64\wheel\.\log_corp1-1.0.1-py3.11.egg-info
running install_scripts
creating build\bdist.win-amd64\wheel\log_corp1-1.0.1.dist-info\WHEEL
creating 'C:\Users\L\Desktop\log_corp_comp1\dist\.tmp-ryh5ya6f\log_corp1-1.0.1-py3-none-any.whl' and adding 'build\bdist.win-amd64\wheel' to it
adding 'log_corp/module1.py'
adding 'log_corp/sub_pkg1/sub_module1.py'
adding 'log_corp1-1.0.1.dist-info/METADATA'
adding 'log_corp1-1.0.1.dist-info/WHEEL'
adding 'log_corp1-1.0.1.dist-info/top_level.txt'
adding 'log_corp1-1.0.1.dist-info/RECORD'
removing build\bdist.win-amd64\wheel
Successfully built log_corp1-1.0.1.tar.gz and log_corp1-1.0.1-py3-none-any.whl
PS C:\Users\L\Desktop\log_corp_comp1>

团队 2(存储库 2)

src 布局

LOG_CORP_COMP2/
├── src/
│   └── log_corp/
│       ├── sub_pkg2/
│       │   └── sub_module2.py
│       └── module2.py
├── pyproject.toml
└── README.md

module2.py

def func2():
    print('From log-corp module2')

sub_module2.py

def sub_func2():
    print('From log-corp submodule2')

pyproject.toml 文件

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "log-corp2"   # Different package name from the previous one
authors = [
    {name = "Logesh", email = "log@gmail.com"},
]
description = "My package description"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT License"}
classifiers = [
    "Programming Language :: Python :: 3",
]
version = "1.0.2"   # Different version 

构建了软件包

PS E:\Documents\log_corp_comp2> ls


    Directory: E:\Documents\log_corp_comp2


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        12/28/2024  11:25 AM                src
-a----        12/28/2024  11:31 AM             34 README.md
-a----        12/28/2024  11:41 AM            387 pyproject.toml


PS E:\Documents\log_corp_comp2> python -m build
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for sdist...
running egg_info
creating src\log_corp2.egg-info
writing src\log_corp2.egg-info\PKG-INFO
writing dependency_links to src\log_corp2.egg-info\dependency_links.txt
writing top-level names to src\log_corp2.egg-info\top_level.txt
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
reading manifest file 'src\log_corp2.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
* Building sdist...
running sdist
running egg_info
writing src\log_corp2.egg-info\PKG-INFO
writing dependency_links to src\log_corp2.egg-info\dependency_links.txt
writing top-level names to src\log_corp2.egg-info\top_level.txt
reading manifest file 'src\log_corp2.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
running check
creating log_corp2-1.0.2
creating log_corp2-1.0.2\src\log_corp
creating log_corp2-1.0.2\src\log_corp2.egg-info
creating log_corp2-1.0.2\src\log_corp\sub_pkg2
copying files to log_corp2-1.0.2...
copying README.md -> log_corp2-1.0.2
copying pyproject.toml -> log_corp2-1.0.2
copying src\log_corp\module2.py -> log_corp2-1.0.2\src\log_corp
copying src\log_corp2.egg-info\PKG-INFO -> log_corp2-1.0.2\src\log_corp2.egg-info
copying src\log_corp2.egg-info\SOURCES.txt -> log_corp2-1.0.2\src\log_corp2.egg-info
copying src\log_corp2.egg-info\dependency_links.txt -> log_corp2-1.0.2\src\log_corp2.egg-info
copying src\log_corp2.egg-info\top_level.txt -> log_corp2-1.0.2\src\log_corp2.egg-info
copying src\log_corp\sub_pkg2\sub_module2.py -> log_corp2-1.0.2\src\log_corp\sub_pkg2
Writing log_corp2-1.0.2\setup.cfg
Creating tar archive
removing 'log_corp2-1.0.2' (and everything under it)
* Building wheel from sdist
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for wheel...
running egg_info
writing src\log_corp2.egg-info\PKG-INFO
writing dependency_links to src\log_corp2.egg-info\dependency_links.txt
writing top-level names to src\log_corp2.egg-info\top_level.txt
reading manifest file 'src\log_corp2.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
* Building wheel...
running bdist_wheel
running build
running build_py
creating build\lib\log_corp
copying src\log_corp\module2.py -> build\lib\log_corp
creating build\lib\log_corp\sub_pkg2
copying src\log_corp\sub_pkg2\sub_module2.py -> build\lib\log_corp\sub_pkg2
running egg_info
writing src\log_corp2.egg-info\PKG-INFO
writing dependency_links to src\log_corp2.egg-info\dependency_links.txt
writing top-level names to src\log_corp2.egg-info\top_level.txt
reading manifest file 'src\log_corp2.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
installing to build\bdist.win-amd64\wheel
running install
running install_lib
creating build\bdist.win-amd64\wheel
creating build\bdist.win-amd64\wheel\log_corp
copying build\lib\log_corp\module2.py -> build\bdist.win-amd64\wheel\.\log_corp
creating build\bdist.win-amd64\wheel\log_corp\sub_pkg2
copying build\lib\log_corp\sub_pkg2\sub_module2.py -> build\bdist.win-amd64\wheel\.\log_corp\sub_pkg2
running install_egg_info
Copying src\log_corp2.egg-info to build\bdist.win-amd64\wheel\.\log_corp2-1.0.2-py3.11.egg-info
running install_scripts
creating build\bdist.win-amd64\wheel\log_corp2-1.0.2.dist-info\WHEEL
creating 'E:\Documents\log_corp_comp2\dist\.tmp-bn0t41tx\log_corp2-1.0.2-py3-none-any.whl' and adding 'build\bdist.win-amd64\wheel' to it
adding 'log_corp/module2.py'
adding 'log_corp/sub_pkg2/sub_module2.py'
adding 'log_corp2-1.0.2.dist-info/METADATA'
adding 'log_corp2-1.0.2.dist-info/WHEEL'
adding 'log_corp2-1.0.2.dist-info/top_level.txt'
adding 'log_corp2-1.0.2.dist-info/RECORD'
removing build\bdist.win-amd64\wheel
Successfully built log_corp2-1.0.2.tar.gz and log_corp2-1.0.2-py3-none-any.whl
PS E:\Documents\log_corp_comp2>

使用 log_corp

创建虚拟环境。

安装 log-corp 的一个组件

安装 log-corp 的另一个组件

因此,我们安装了 2 个共享相同命名空间的不同包(主包)。所以,现在这两个软件包 log_corp1 log_corp2 可以独立进行开发、分发、安装、升级、版本化。(仍然共享相同的命名空间,即所谓的 Namespace 包。

在这里,源的合并是在安装过程中自动完成的,并且在合并过程中没有冲突。这是使用 Namespace 包的主要好处之一。

log-corp 作为一个整体使用,它是从不同来源安装的。

一个明显的缺点是 import *log_corp 无法按预期工作。

由于没有__init__.py文件来初始化包。

尝试使用常规软件包实现相同的效果

为两个组件添加 __init__.py,并在该文件中进行一些初始化。

组件 1

LOG_CORP_COMP1/
├── src/
│   └── log_corp/
│       ├── sub_pkg1/
│       │   ├── __init__.py
│       │   └── sub_module1.py
│       ├── __init__.py
│       └── module1.py
├── pyproject.toml
└── README.md

log_corp/__init__.py

from . import module1
from . import sub_pkg1

log_corp/sub_pkg1/__init__.py

from . import sub_module1

其余文件具有相同的内容。

组件 2

LOG_CORP_COMP2/
├── src/
│   └── log_corp/
│       ├── sub_pkg2/
│       │   ├── __init__.py
│       │   └── sub_module2.py
│       ├── __init__.py
│       └── module2.py
├── pyproject.toml
└── README.md

log_corp/__init__.py

from . import module2
from . import sub_pkg2

log_corp/sub_pkg2/__init__.py

from . import sub_module2

其余文件具有相同的内容。

构建两个软件包

组件 1

PS C:\Users\L\Desktop\log_corp_comp1> python -m build
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for sdist...
running egg_info
creating src\log_corp1.egg-info
<...truncated output>
removing build\bdist.win-amd64\wheel
Successfully built log_corp1-1.0.1.tar.gz and log_corp1-1.0.1-py3-none-any.whl
PS C:\Users\L\Desktop\log_corp_comp1>
PS C:\Users\L\Desktop\log_corp_comp1> ls


    Directory: C:\Users\L\Desktop\log_corp_comp1


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        12/28/2024   1:31 PM                dist
d-----        12/28/2024   1:31 PM                src
-a----        12/28/2024  11:41 AM            387 pyproject.toml
-a----        12/28/2024  11:31 AM             34 README.md


PS C:\Users\L\Desktop\log_corp_comp1>

组件 2

PS E:\Documents\log_corp_comp2> python -m build
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for sdist...
running egg_info
creating src\log_corp2.egg-info
writing src\log_corp2.egg-info\PKG-INFO
writing dependency_links to src\log_corp2.egg-info\dependency_links.txt
writing top-level names to src\log_corp2.egg-info\top_level.txt
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
reading manifest file 'src\log_corp2.egg-info\SOURCES.txt'
writing manifest file 'src\log_corp2.egg-info\SOURCES.txt'
* Building sdist...
running sdist
running egg_info
<...truncated output>
Writing log_corp2-1.0.2\setup.cfg
Creating tar archive
removing 'log_corp2-1.0.2' (and everything under it)
* Building wheel from sdist
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
* Getting build dependencies for wheel...
running egg_info
<...truncated output>
Successfully built log_corp2-1.0.2.tar.gz and log_corp2-1.0.2-py3-none-any.whl
PS E:\Documents\log_corp_comp2>

用法

已卸载之前安装的软件包。

安装软件包 log_corp1

在脚本中使用它。

module1 subpkg1 是可访问的

安装软件包 log_corp2

此安装会直接覆盖 log_corp/__init__.py 文件。

现在只有 log_corp2 的模块和子包可用。

但是我们仍然可以从 log_corp1 访问包/模块,将 log_corp 作为主包。

唯一需要注意的是,log_corp/__init__.py log_corp2 覆盖。因此,如果我们有任何来自 log_corp1 的关键初始化将受到影响,这可能会导致包损坏问题。

结论

命名空间包是创建灵活且可扩展的 Python 包的现代方法。它们允许包的多个部分驻留在不同的目录中或分布在多个项目中。这使它们成为大型项目、插件系统或独立开发组件的情况的理想选择。

导入时的行为*

命名空间包不直接支持通配符导入(从 package import *),因为它们缺少 __init__.py 文件,其中常规包通常定义__all__列表来控制导入的内容。

命名空间包的优点

  1. 模块化:包的不同部分可以拆分到多个项目或目录中。
  2. 可扩展性:非常适合带有插件或独立开发组件的大型系统。
  3. 易于维护:支持对包的特定部分进行更新,而不会影响整个结构。
  4. __init__.py要求:简化包的创建并避免不必要的样板文件。
  5. 改进的协作:团队可以并行处理包的不同部分,每个团队都拥有自己的目录。

命名空间包的缺点

  1. __init__.py功能:如果没有 __init__.py 文件,您将无法初始化包、定义默认导入或设置包级逻辑。
  2. 通配符导入的复杂性:不支持 import *,在某些用例中可能会带来不便。
  3. 运行时组合:解析完整的包结构在运行时进行,如果目录配置错误,可能会导致细微的问题。
  4. 调试挑战:由于软件包的各个部分分布在多个位置,因此调试和跟踪问题可能会更加困难。

将命名空间包用于分布式模块化系统或框架。对于更简单的项目或需要与较旧的 Python 版本兼容时,请坚持使用常规包。

相关推荐

Python合集之Python字符串常用操作(一)

在上一节的合集中,我们了解了Python集合增删改及集合间运算的相关知识,本节我们将进一步了解一下Python字符串的常用操作的相关知识。1.拼接字符串使用+运算符可完成对多个字符串的拼接,+运...

Python 入门系列——17. tuple 简介

tupletuple常用来将多个item放在一个变量中,同时tuple也是python4个集合类型之一,其他的三个是:List,Set,Dictionary,它们都有自己的用途和场景。tupl...

Python基础 - 变量的作用域(python中变量由什么组成)

变量的作用域决定了变量在程序中的可见性和生命周期。在Python中,变量的作用域有以下几种:局部作用域(当前函数内部)嵌套作用域(外层函数)全局作用域(模块级别)内置作用域(Python的内置函数和内...

Python中冷门但非常好用的内置函数

Python中有许多内置函数,不像print、len那么广为人知,但它们的功能却异常强大,用好了可以大大提高代码效率,同时提升代码的简洁度,增强可阅读性Countercollections在pytho...

Python常用函数整理(python常用函数大全pdf)

以下是Python中常用函数整理,涵盖内置函数、标准库及常用操作,按类别分类并附带示例说明:一、基础内置函数print()输出内容到控制台。pythonprint("Hello,World!")#...

新手易犯错的地方Python作用域(python作用域和命名空间)

好多新手一开始比较容易犯错的地方理解作用域对于编写高效的python代码十分重要现在就讲下四种作用域,按照从内到外的顺序:局部作用域(Local)-在函数内部定义的变量嵌套作用域(Enclosin...

函数与模块:Python编程中的核心工具

一、函数的定义与核心概念1.1函数的定义函数是封装可重复执行代码的模块化单元,通过命名的方式组织代码逻辑,实现代码复用和功能解耦(将不同功能独立开来,减少代码之间的依赖关系)。其基本语法结构为:de...

太好用!教你几招Python魔法方法的妙用

专注Python、AI、大数据,请关注公众号七步编程!Python是一种简单的编程语言,满足一个需求,可以有各种各样的实现方法。正是因为它可以通过各种串联满足很多复杂的逻辑,因此,对代码可读性关注度不...

深入解析Python中的range()函数(python里面range函数)

range()是Python中一个非常基础且功能强大的内置函数,广泛用于循环控制和数字序列生成。它在迭代、索引处理和循环次数控制中扮演重要角色。本文将从基础用法到高级技巧,全面解析range()的使用...

站长在线python精讲在Python中使用len()函数计算字符串长度详解

欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是《在Python中使用len()函数计算字符串的长度详解》。本知识点主要内容有:在Python中使用len()函数计算字符串在UTF-8编...

linux工作中常用之必备基础命令(二)

1、clear命令功能说明:清屏。举例:clear;ctrl+l2、who命令功能说明:当前在本地系统上的所有用户的信息举例:whoami;who3、uptime命令功能说明:查询系统...

CentOS7装Ollama,本以为小菜一碟,没想到掉坑里了!

今天准备在CentOS7上安装Ollama,原本以为是小事一桩。哪想还是遇上了点小麻烦。因为在Windows上安装Ollama太小儿科了,上ollama.com网站下载程序,一键安装即可,最多就是设...

Linux下 sudo命令(linux里sudo怎么用)

平常使用Linux的时候,都是用普通用户登录执行命令,但是有些命令需要root权限才能执行,如果切换到root用户去执行,就需要输入root密码,为了系统的安全性,应该尽可能少的直接在终端上输入roo...

CentOS7.3 Linux系统中杀死进程的方法

CentOS7.3学习笔记总结(二十四)-Centoslinux系统中杀死进程的方法在工作中,我常常需要终止有问题的进程,一般通过程序的关闭命令把进程关闭掉,这是最安全的方法,但是有些时候,我们无法...

Linux(CentOs7)防火墙命令,两种使用方式示例

一、CentOs7关闭防火墙的命令1:查看防火状态systemctlstatusfirewalldserviceiptablesstatus2:暂时关闭防火墙systemctlstop...