Skip to content

Latest commit

 

History

History
199 lines (101 loc) · 4.89 KB

模块的预设字段.md

File metadata and controls

199 lines (101 loc) · 4.89 KB

模块的预设字段

python中所有东西都是对象,模块也不例外,在一个模块被导入后它就是作为一个对象而存在的,但这个对象有点特殊

  1. 无论加载多少次,它都是唯一对象.
  2. 每个模块都有一些特殊的字段,和python中类的魔术命令差不多,他们可以用来对模块自省

本文主要介绍这些特殊字段

我们以一个模块作为例子来观察.其结构如下:

module_test|
           |-__init__.py
           |-a|
              |-__init__.py
              |-b.py

其中module_test.__init__.py为:

"""这就是一个测试."""
from pathlib import Path

path=Path(__file__)
if path.exists():
    dir_path = path.absolute().parent
    __path__.append(str(dir_path.joinpath("a")))

b.py为

def func():
    return 1


__all__ = ["func"]
import module_test
from module_test import a

__name__字段用于自省模块的名字

一旦某个模块被导入后,他的__name__字段就会保存从其所在包的起点位置到自身的引用关系以组成自身的名字.这个规则有点类似java中的模块概念.

特别的是所有的入口模块其名都为__main__

print(__name__)
print(module_test.__name__)
print(a.__name__)
__main__
module_test
module_test.a

__doc__字段用于自省模块的docstring

模块的__doc__字段用于自省模块的docstring,

print(module_test.__doc__)
这就是一个测试.

__all__字段用于设置模块的导入范围

__all__是用于限制模块使用from xxxx import *这样形式的模块导入语法的导入对象范围的字段.在要进行限制的模块下设置

__all__:List[str] = ["asfd"]

使用与对象同名的字符串指代可以进行导入的对象.这样这种语法下就可以对导入进行限制,一定程度上防止命名空间被污染

__path__字段用于自省模块的所在绝对地址

这个关键字只对package有意义,入口模块是没有这个字段的,访问也会报错,需要注意.

__path__字段是在加载时被创建的,可以记录其所在的绝对地址.,注意它是一个List[str]数据.

__path__字段会影响导入时对包中包含的模块和子包的搜索.比如在module_test中为__path__添加一个子模块的路径,他就会同时导入这个子模块

module_test.__path__
['/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test',
 '/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test/a']

__file__用于自省被引用模块文件的路径

如果当前文件包含在sys.path里面,那么,__file__返回一个相对路径;

如果当前文件不包含在sys.path里面,那么__file__返回一个绝对路径.

module_test.__file__
'/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test/__init__.py'

__package__用于自省所在的包位置

__package__只有package中才会有,入口模块中__package__为空.__package__主要是为了相对引用而设置的一个属性, 如果所在的文件是一个package的话, 它和__name__的值是一样的, 如果是子模块的话, 它的值就跟父模块一致

print(module_test.__package__)
print(a.__package__)
module_test
module_test.a

__spec__模块规范对象

module_test.__spec__
ModuleSpec(name='module_test', loader=<_frozen_importlib_external.SourceFileLoader object at 0x10666c7b8>, origin='/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test/__init__.py', submodule_search_locations=['/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test', '/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test/a'])

__loader__模块加载器

模块使用模块加载器加载进python的虚拟机,而__loader__则是自省导入时使用加载器的字段.此处不多扩展,在下一篇中我们会详细介绍模块的加载流程以及如何利用这一流程做一些特殊的事情.

module_test.__loader__
<_frozen_importlib_external.SourceFileLoader at 0x10666c7b8>

__cached__ 模块是否已经缓存

如果已经缓存的话,则会保存模块对应.pyc的绝对地址

module_test.__cached__
'/Users/huangsizhe/WORKSPACE/github/hsz1273327/TutorialForPython/ipynbs/语法篇/模块/module_test/__pycache__/__init__.cpython-36.pyc'

__dict__用于自省模块中所有字段

和python的其他对象一样,__dict__用于自省模块对象中所有的字段.

本文只是先将这些字段罗列出来便于查找后面的小节中我们会详细介绍模块的加载流程.