Weibw's World Weibw's World
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Weibw

一个没有梦想的咸鱼
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《Flask》

  • 《Python Cookbook》第三版

    • 第一章:数据结构与算法

    • 第二章:字符串和文本

    • 第三章:数字日期和时间

    • 第四章:迭代器与生成器

    • 第五章:文件与IO

    • 第六章:数据编码和处理

    • 第七章:函数

    • 第八章:类与对象

    • 第九章:元编程

    • 第十章:模块与包

      • 构建一个模块的层级包
      • 控制模块被全部导入的内容
      • 使用相对路径名导入包中子模块
      • 将模块分割成多个文件
      • 利用命名空间导入目录分散的代码
        • 问题
        • 解决方案
        • 讨论
      • 重新加载模块
      • 运行目录或压缩文件
      • 读取位于包中的数据文件
      • 将文件夹加入到syspath
      • 通过字符串名导入模块
      • 通过钩子远程加载模块
      • 导入模块的同时修改模块
      • 安装私有的包
      • 创建新的Python环境
      • 分发包
    • 第十一章:网络与Web编程

    • 第十二章:并发编程

    • 第十三章:脚本编程与系统管理

    • 第十四章:测试、调试和异常

    • 第十五章:C语言扩展

  • Python基础

  • Python
  • 《Python Cookbook》第三版
  • 第十章:模块与包
weibw
2022-01-18

利用命名空间导入目录分散的代码

# 问题

你可能有大量的代码,由不同的人来分散地维护。每个部分被组织为文件目录,如一个包。然而,你希望能用共同的包前缀将所有组件连接起来,不是将每一个部分作为独立的包来安装。

# 解决方案

从本质上讲,你要定义一个顶级Python包,作为一个大集合分开维护子包的命名空间。这个问题经常出现在大的应用框架中,框架开发者希望鼓励用户发布插件或附加包。

在统一不同的目录里统一相同的命名空间,但是要删去用来将组件联合起来的__init__.py文件。假设你有Python代码的两个不同的目录如下:

foo-package/
    spam/
        blah.py

bar-package/
    spam/
        grok.py
1
2
3
4
5
6
7

在这2个目录里,都有着共同的命名空间spam。在任何一个目录里都没有__init__.py文件。

让我们看看,如果将foo-package和bar-package都加到python模块路径并尝试导入会发生什么

>>> import sys
>>> sys.path.extend(['foo-package', 'bar-package'])
>>> import spam.blah
>>> import spam.grok
>>>
1
2
3
4
5

两个不同的包目录被合并到一起,你可以导入spam.blah和spam.grok,并且它们能够工作。

# 讨论

在这里工作的机制被称为“包命名空间”的一个特征。从本质上讲,包命名空间是一种特殊的封装设计,为合并不同的目录的代码到一个共同的命名空间。对于大的框架,这可能是有用的,因为它允许一个框架的部分被单独地安装下载。它也使人们能够轻松地为这样的框架编写第三方附加组件和其他扩展。

包命名空间的关键是确保顶级目录中没有__init__.py文件来作为共同的命名空间。缺失__init__.py文件使得在导入包的时候会发生有趣的事情:这并没有产生错误,解释器创建了一个由所有包含匹配包名的目录组成的列表。特殊的包命名空间模块被创建,只读的目录列表副本被存储在其__path__变量中。 举个例子:

>>> import spam
>>> spam.__path__
_NamespacePath(['foo-package/spam', 'bar-package/spam'])
>>>
1
2
3
4

在定位包的子组件时,目录__path__将被用到(例如, 当导入spam.grok或者spam.blah的时候).

包命名空间的一个重要特点是任何人都可以用自己的代码来扩展命名空间。举个例子,假设你自己的代码目录像这样:

my-package/
    spam/
        custom.py
1
2
3

如果你将你的代码目录和其他包一起添加到sys.path,这将无缝地合并到别的spam包目录中:

>>> import spam.custom
>>> import spam.grok
>>> import spam.blah
>>>
1
2
3
4

一个包是否被作为一个包命名空间的主要方法是检查其__file__属性。如果没有,那包是个命名空间。这也可以由其字符表现形式中的“namespace”这个词体现出来。

>>> spam.__file__
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute '__file__'
>>> spam
<module 'spam' (namespace)>
>>>
1
2
3
4
5
6
7

更多的包命名空间信息可以查看 PEP 420 (opens new window).

编辑 (opens new window)
上次更新: 2023/10/13, 17:39:25
将模块分割成多个文件
重新加载模块

← 将模块分割成多个文件 重新加载模块→

最近更新
01
牛客网非技术快速入门SQL练习题
03-08
02
其他日常SQL题
03-07
03
用户与权限管理
03-05
更多文章>
Theme by Vdoing | Copyright © 2021-2023 | Weibw | 辽ICP备18015889号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式