信息化建设办公室网站/seo网站推广优化论文
包和模块
首先要介绍Python中两个概念:包和模块。简单的理解(从文档系统角度),包(package)是一个文档夹,而模块(module)是一个python源码文档(扩展名为.py)。包(package):文档夹(文档夹中含有文档__init__.py),包里面含有很多模块组成。__init__.py文档,在里面自定义初始化操作,或为空。
模块(module):即python文档,文档中定义了函数、变量、常量、类等。
Import 方法
Import 模块方法
先看一个例子。我们经常使用的模块math ,背后对应其实是一个python文档:math.py 。该文档在C:Anaconda3Libsite-packagespymc3目录里面(具体环境会有差异)。1
2
3import math
math.sqrt(2)
如果只要import math.py中具体的函数:1
2
3from math import sqrt,sin
sqrt(2)
sin(1)
另外可以将模块中所有内容导入:1
2from math import *
sqrt(2)
Import 包方法
包(package)可以简单理解为文档夹。该文档夹下须存在 __init__.py 文档, 内容可以为空。另外该主文档夹下面可以有子文档夹,如果也有 __init__.py 文档,这是子包。类似依次嵌套。
例如Tensorflow的包(文档树):1
2
3
4
5
6
7
8
9
10
11
12[email protected]:~/anaconda3/lib/python3.6/site-packages/tensorflow# tree -L 1
.
├── aux-bin
├── contrib
├── core
├── examples
├── include
├── __init__.py
├── libtensorflow_framework.so
├── __pycache__
├── python
└── tools__init__.py 文档在import包时,优先导入,作为import包的初始化。
我们以Tensorflow为例:1
2
3
4
5
6
7
8import tensorflow as tf
import tensorflow.contrib as contrib
from tensorflow import contrib
from tensorflow.examples.tutorials import mnist
import tensorflow.examples.tutorials.mnist
命名空间(namespace)
Namespace是字典数据,供编译器、解释器对源代码中函数名、变量名、模块名等信息进行关联检索。
定义
Python语言使用namespace(命名空间)来存储变量,namespace是一个mapping(映射)。namespace可以理解是一个字典(dict)数据类型,其中键名(key)为变量名,而键值(value)为变量的值。A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries。每一个函数拥有自己的namespace。称为local namespace(局部命名空间),记录函数的变量。
每一个模块(module)拥有自己的namespace。称为global namespace(全局命名空间),记录模块的变量,包括包括模块中的函数、类,其他import(导入)的模块,还有模块级别的变量和常量。
每一个包(package)拥有自己的namespace。 也是global namespace ,记录包中所有子包、模块的变量信息。
Python的built-in names(内置函数、内置常量、内置类型)。 即内置命名空间。在Python解释器启动时创建,任何模块都可以访问。当退出解释器后删除。
命名空间的检索顺序
当代码中需要访问或获取变量时(还有模块名、函数名),Python解释器会对命名空间进行顺序检索,直到根据键名(变量名)找到键值(变量值)。查找的顺序为(LEGB):local namespace,即当前函数或者当前类。如找到,停止检索。
enclosing function namespace,嵌套函数中外部函数的namespace。
global namespace,即当前模块。如找到,停止检索。
build-in namespace,即内置命名空间。如果前面两次检索均为找到,解释器才会最后检索内置命名空间。如果仍然未找到就会报NameRrror(类似:NameError: name 'a' is not defined)。
举栗子
讲完了理论介绍,我们来举栗子,直观感受一下。1
2
3
4
5
6
7
8
9
10
11
12
13进入python环境
Python 3.5.3 |Anaconda custom (64-bit)| (default, May 11 2017, 13:52:01) [MSC v.
1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>> print(globals())
{'__name__': '__main__', '__doc__': None, '__spec__': None, '__package__': None,
'__loader__': , '__builtins__':
ule 'builtins' (built-in)>}
>>> x=1
>>> print(globals())
{'__name__': '__main__', '__doc__': None, '__spec__': None, '__package__': None,
'__loader__': , '__builtins__':
ule 'builtins' (built-in)>, 'x': 1}
上面的例子我们查看了global namespace的字典(dict),其中'__builtins__'就是内置命名空间。新建变量x=1后,全局命名空间会新增这个K-V对。
还可以通过下面的方法查看import模块、包的namespace。
当我们import一个module(模块)或者package(包)时,伴随着新建一个global namespace(全局命名空间)。1
2
3
4
5
6
7
8
9
10
11import math
math.__dict__
{'__name__': 'math', 'tanh': , 'nan': nan, 'atanh':
lt-in function atanh>,'acosh': ,
#中间略
'trunc': , 'acos': , 'sqrt':
function sqrt>, 'floor': , 'gamma':
gamma>, 'cosh': }
import tensorflow
tensorflow.__dict__
#包的所有模块、函数等命名空间信息。大家可以试一下。
大家可以动手试试其他的场景,比如函数内部查看locals() 。函数内部的变量global声明后,查看globals()字典会有怎样变化。这里就不再一一验证举栗了。
对于包,我们以tensorflow为例:1
2
3
4
5
6import tensorflow
tensorflow.__dict__
##中间略,只摘取部分信息。命名空间中包含module和function的信息。
'angle': ,
'app': ,
'arg_max': ,
Import的过程
当我们执行import 模块、包时,主要有三个过程:检索、加载、名字绑定。
第一步:检索(Finder)
Python解释器会对模块所属位置进行搜索:
(1)检索:内置模块(已经加载到缓存中的模块)
内置模块(已经加载到缓存中的模块),即在 sys.modules 中检索。Python已经加载到内存中的模块均会在这个字典中进行登记。如果已经登记,不再重复加载。直接将模块的名字加入正在import的模块的namespace。可以通过下面方法查看:1
2
3
4
5
6
7
8
9>>> import sys
>>> print(sys.modules)
{'_signal': , 'os.path':
Anaconda3\lib\ntpath.py'>,pickle': ,
#中间略
'subprocess':module 'subprocess' from 'C:\Anaconda3\lib\subprocess.py'>, 'sys':
ys' (built-in)>, 'ctypes.util':
ctypes\util.py'>, '_weakref': , '_imp':
_imp' (built-in)>}如果不是built-in,value中会有模块的绝对路径信息。
通过key查找模块位置,如果value为None,就会抛出错误信息:ModuleNotFoundError。
如果key不存在,就会进入下一步检索。
如果我们导入过包,例如tensorflow。
注意如果要使用其中模块,需要该模块的全名(即全路径信息),例如:tensorflow.examples.tutorials.mnist.input_data 。因为sys.modules中只有全路径的key。1
2
3
4import tensorflow
print(sys.modules)
##这个字典中会有tensorflow所有子包、模块的信息和具体的路径。
#'tensorflow.examples.tutorials.mnist.input_data':
逐个遍历其中的 finder 来查找模块。否则进入下一步检索。
(3)检索模块所属包目录
如果模块Module在包(Package)中(如import Package.Module),则以Package.__path__为搜索路径进行查找。
(4)检索环境变量
如果模块不在一个包中(如import Module),则以 sys.path 为搜索路径进行查找。如果上面检索均为找到,抛出错误信息:ModuleNotFoundError。
第二步:加载(Loader)
加载完成对模块的初始化处理:设置属性。包括__name__、__file__、__package__和__loader__ 。编译源码。编译生成字节码文档(.pyc文档),如果是包,则是其对应的__init__.py文档编译为字节码(*.pyc)。如果字节码文档已存在且仍然是最新的(时间戳和py文档一致),则不会重新编译。加载到内存。模块在第一次被加载时被编译,载入内存,并将信息加入到sys.modules中。也可以强制用reload()函数重新加载模块(包)。
第三步:名字绑定
将模块和包的命名空间信息导入到当前执行Python文档的namespace(命名空间)。
将模块、包的路径加入检索路径
讲完了枯燥的理论背景,下面我们来介绍实际应用。当你写好一个模块文档,如何正确完成import模块?主要有下面两类方法:
动态方法(sys.path中添加)
我们知道检索路径中sys.path,所以可以在import模块之前将模块的绝对路径添加到sys.path中。同样导入包需要加入包的文档夹绝对路径。具体方法如下:1
2
3
4
5import sys
##sys.path.append(dir)
sys.path.append('yourmodule(package)filepath')
##sys.path.insert(pos,dir)
sys.path.insert(0,'yourmodule(package)filepath')1
2
3
4
5
6
7
8
9#win7
import sys
print(sys.path)
#输出
['', 'C:\Python27\lib\site-packages\pip-8.1.1-py2.7.egg', 'C:\windows\syst
em32\python27.zip', 'C:\Python27\DLLs', 'C:\Python27\lib', 'C:\Python27\l
ib\plat-win', 'C:\Python27\lib\lib-tk', 'C:\Python27', 'C:\Users\rongxian
g\AppData\Roaming\Python\Python27\site-packages', 'C:\Python27\lib\site-
packages']
静态方法
(1)另外检索路径还有系统环境变量,所以可以将模块(包)路径添加在系统环境变量中。
(2)粗暴一点直接将模块(包)拷贝到sys.path的其中一个路径下面。但是这种管理比较乱。
(3)Python在遍历sys.path的目录过程中,会解析 .pth 文档,将文档中所记录的路径加入到 sys.path ,这样 .pth 文档中的路径也可以找到了。例如我们在C:Python27libsite-packages 中新建一个.pth文档。例如:1
2# .pth file for the your module or package
'yourmodule(package)filepath'
这样在模块(包)上线时,我们只需要将模块(包)的目录或者文档绝对路径放在新建的.path文档中即可。
参考文章