一个python代码文件,就是一个模块。
文件名就是模块名,在模块内部,全局变量name获取。
目的是为了代码的组织和复用。
每个模块都有自己的符号表,存储模块中定义函数、全局变量的名字,通过名字就可以访问对应的函数、全局变量,类似Lua的环境表。
导入模块
模块可以导入其它模块。被导入的模块名存放在调入模块的全局符号表中。
处于效率考虑,重复import只会执行一次,可以通过importlib.reload重载模块,见下面介绍。
import module1[, module2[,... moduleN]]
# 比如import module1
# 将module1模块名存在当前模块的符号表中,通过module1就可获得module1的模块符号表
# 通过符号表就可访问其内部定义的函数、全局变量
# module1:只能是包、模块
# import a.b.c.d时,a、b、c必须是包,d可以是模块/包,d不可以是c中定义的名字。
#
import module1 as newmodname
# 效果同上,只是将新名字newmodname绑定到模块上。
from modname import name1[, name2[, ... nameN]]
# 将模块modname内的名字导入到当前模块的符号表中,类似C++ using std::cout的效果
# 通过名字可直接访问到模块monname中对应定义的函数、全局变量。
# modname:可能是包、模块
# nameN: 可能是子模块,也可能是模块中定义的名字(函数、变量、模块)
# from a.b.c import d,则可直接通过d来访问,不需要麻烦的a.b.c.d
from modname import name1 as newname
# 效果同上,只是将新名字绑定到name1绑定的内容上。
from modname import *
# 将模块modname内定义的所有名字导入到当前模块的符号表中,类似C++ using namespace::std的效果。
# _下划线开头的名字也会被导入。
# 不建议这么做,极易导致符号表名字冲突而发生覆盖。
#********************fucker.py
def shit():
print("shit")
shit();
#********************test.py
import fucker
fucker.shit()
from fucker import shit
shit()
模块?脚本?
一个python代码文件既可以看成模块,也可以看成脚本。
当在代码中import时,这个文件被当做模块。
当通过命令行执行文件时,它是一个脚本。
这有什么意义?见如下代码:
#############test.py
def fuck(*args):
for arg in args:
print(arg)
#加上下面这段逻辑,则test.py即可当脚本也可以当模块使用。
if __name__ == "__main__": #当做脚本使用时,__name__ = __main__
#当做模块使用时,__name__ = test
import sys
fuck(*sys.argv)
#############在run.py中,被当做模块使用
from test import fuck
fuck(1, 2, 3, 4)
#############在window cmd中,被当做脚本使用
>> python test.py 1 2 3 4
<< test.py
<< 1
<< 2
<< 3
<< 4
模块搜索路径
import test,解释器查找test模块过程如下:
- 在内置模块中查找
- 在sys.path变量中查找test.py,它是一个字符串列表,初始值如下:
- 输入脚本目录(或者未指定文件时的当前目录),即正在运行脚本的目录。
- 环境变量PYTHONPATH中的每个目录
- windows:举个例子,PYTHONPATH=c:\python27\lib;
- UNIX:举个例子,PYTHONPATH=/usr/local/lib/python
- 默认路径
- 安装python时设定
- UNIX下,默认是/usr/local/lib/python/。
我们可以修改sys.path变量,来改变搜索路径。
import sys
sys.path.append('/ufs/guido/lib/python')
列出模块内名字:dir
sortedlst = dir(module=None)
# 返回module中定义的所有名字(函数、模块、变量),返回的是一个排好序的列表。
# 不会返回内置的名字。
# 默认返回当前模块的名字,
import math
content = dir(math)
cur = dir()
print content;
['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan',
'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp',
'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh',
'sqrt', 'tan', 'tanh']
import builtins
dir(builtins) #列出内置的名字。
缓存模块:pycache
为了加快模块载入,python在pycache 目录里缓存了每个模块的编译后版本,名称为 module.version.pyc ,
- verson
- 版本字段,它一般使用Python版本号。例如,在CPython版本3.3中,spam.py的编译版本将被缓存为 pycache/spam.cpython-33.pyc。此命名约定允许来自不同发行版和不同版本的Python的已编译模块共存。
python根据源文件的修改日期,和pyc编译版本比对来决定是否需要重新编译。pyc文件时平台无关的,可以不同平台共享。
Python在两种情况下不会检查缓存。首先,对于从命令行直接载入的模块,它从来都是重新编译并且不存储编译结果;其次,如果没有源模块,它不会检查缓存。为了支持无源文件(仅编译)发行版本, 编译模块必须是在源目录下,并且绝对不能有源模块。
- 小建议
fuck1() #顶层代码
#######shit.py
from importlib import reload import fuck1 #输出:fuck1 import fuck1 #没有输出
reload(fuck1) #输出:fuck1
<a name="4aDpr"></a>
# 包(Package)
包是python的一种机制,用来构造模块的命名空间,你可以类比C++的namespace。<br />不同的命名空间内的名字可以一样。<br />必须要包含有__init__.py文件的目录,才能被当作包,这个文件可以看成包的初始化文件。可以在里面执行初始化逻辑。<br />所以可以把目录看成包,把代码文件看成模块。
```python
#在C++中
# A::B,A、B都是命名空间,表示A中的B命名空间。
# using A::B,就可以直接使用B中定义的名字了。
#在python中
# A.B,表示A包中的B模块。
# import A.B,导入了A包中的B模块。
'''
目录结构如下:
test.py
test2.py
dir1/
__init__.py
fuck11.py 里面有一个fuck11函数,打印fuck11
fuck12.py 里面有一个fuck12函数,打印fuck12
dir2/ 子包
__init__.py
fuck21.py 里面有一个fuck21函数,打印fuck21
fuck21.py 里面有一个fuck22函数,打印fuck22
dir3/ 子包
__init__.py
fuck31.py 里面有一个fuck31函数,打印fuck31
fuck32.py 里面有一个fuck32函数,打印fuck32
'''
###############在test.py文件中,绝对导入,
from dir1.fuck11 import fuck11
from dir1.dir2.fuck21 import fuck21
fuck11() #输出fuck11
fuck21() #输出fuck21
###############在fuck31.py中,相对导入
from ..dir2.fuck21 import fuck21 #导入fuck21函数
from .. import dir2 #导入父目录下的dir2包
from . import fuck31 #导入同目录下的fuck31模块
#在主模块中,必须使用绝对导入,因为相对导入是基于当前模块的名称导入的
#而主模块的名字一直是"__main__"。
#主模块就是那个从命令行启动的模块,也就是以脚本启动的模块,一般是程序的入口。
###############test2.py
#在dir1/__init__.py中代码如下:
__all__ = [ #__all__变量,包含当前所在包的所有子部分(子包、子模块、定义的名字)
"fuck11" #决定了import *的导入内容。
]
from dir1 import * #只会导入fuck11模块。