首页 > 技术文章 > [python] 包管理

swxs 2019-07-06 23:28 原文

最近感觉得把之前的一些知识做下总结, 后面将一块内容以可以清楚表述为标准进行判断是否掌握

python 包管理个人感觉是包含PEP382[1] (PEP420[2]中完善)为分界的两个版本

第一版,在PEP382之前,主要的包管理模式为 [常规包] 形式, 主要特征为默认包含 __init__.py 文件作为一个python包

第二版,在PEP420之后,[命名空间包]相对成熟, 支持模块导入 (PEP382就开始支持, 但是PEP420之后功能完善), 特征为支持 -m 参数作为模块导入

 

个人认为 命名空间包 的主要优势在于支持相对导入 见下面文件结构

 1 text = "print(f'__name__: {__name__}, __file__: {__file__}, __package__: {repr(__package__)}')"
 2 
 3 from pathlib import Path
 4 Path('foo.py').write_text(text)
 5 Path('package').mkdir()
 6 Path('package/__init__.py').write_text(text)
 7 Path('package/__main__.py').write_text(text)
 8 Path('package/bar.py').write_text(text)
 9 
10 # and include a submodule with a relative import:
11 Path('package/baz.py').write_text(text + '\nfrom . import bar')

分别在最外层以两种模式实验运行baz.py模块

在包含__init__.py文件时, 两种情况可以实现相同功能

python3 package/baz.py
'''
__main__, __file__: package/baz.py, __package__: None
Traceback (most recent call last):
  File "package/baz.py", line 5, in <module>
    from package import bar
ModuleNotFoundError: No module named 'package'
'''

python3 -m package.baz
'''
package, __file__: /data/path/package/__init__.py, __package__: 'package'
__main__, __file__: /data/path/package/baz.py, __package__: 'package'
package.bar, __file__: /data/path/package/bar.py, __package__: 'package'
'''

可以看到第一种模式出错了, 这主要是因为package这个模块不在sys.path中,我们可以将其设为 sys.path的第一个值 来成功运行, 添加如下代码,  可以看到其顺利运行了,

之前我这边的老脚本都是这种机制实现的

import os
import sys
if __name__ == '__main__':
    sys.path.insert(0, os.path.abspath(os.curdir))


python3 package/baz.py
__main__, __file__: package/baz.py, __package__: None
package, __file__: /data/path/package/__init__.py, __package__: 'package'
package.bar, __file__: /data/path/package/bar.py, __package__: 'package'

如今基于 -m 的 命名空间包 机制, 省去的这个麻烦

 

下面讲下__main__.py文件,

见上方 模块运行的例子, 可以看到虽然先调用了 package/__init__.py文件, 但是在调用package/baz.py的时候其才是__main__, 所以可以判断__name__ == "__main__"

那么__main__.py什么时候运行呢, 答案是通过 python -m package 的时候, 会在__init__.py 运行之后运行,基于这种机制, 以后可以创建__main__.py文件,整个脚本代码更为简洁,(少了判断)

 

以后有空讲讲 __import__, import_module, 第三方库如何实现自定义的文件加载这些内容

 

[1]  PEP382:https://www.python.org/dev/peps/pep-0382/

[2]  PEP420:https://www.python.org/dev/peps/pep-0420/

推荐阅读