一个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.dfrom modname import name1 as newname# 效果同上,只是将新名字绑定到name1绑定的内容上。from modname import *# 将模块modname内定义的所有名字导入到当前模块的符号表中,类似C++ using namespace::std的效果。# _下划线开头的名字也会被导入。# 不建议这么做,极易导致符号表名字冲突而发生覆盖。
#********************fucker.pydef shit():print("shit")shit();#********************test.pyimport fuckerfucker.shit()from fucker import shitshit()
模块?脚本?
一个python代码文件既可以看成模块,也可以看成脚本。
当在代码中import时,这个文件被当做模块。
当通过命令行执行文件时,它是一个脚本。
这有什么意义?见如下代码:
#############test.pydef fuck(*args):for arg in args:print(arg)#加上下面这段逻辑,则test.py即可当脚本也可以当模块使用。if __name__ == "__main__": #当做脚本使用时,__name__ = __main__#当做模块使用时,__name__ = testimport sysfuck(*sys.argv)#############在run.py中,被当做模块使用from test import fuckfuck(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 syssys.path.append('/ufs/guido/lib/python')
列出模块内名字:dir
sortedlst = dir(module=None)# 返回module中定义的所有名字(函数、模块、变量),返回的是一个排好序的列表。# 不会返回内置的名字。# 默认返回当前模块的名字,import mathcontent = 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 builtinsdir(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.pytest2.pydir1/__init__.pyfuck11.py 里面有一个fuck11函数,打印fuck11fuck12.py 里面有一个fuck12函数,打印fuck12dir2/ 子包__init__.pyfuck21.py 里面有一个fuck21函数,打印fuck21fuck21.py 里面有一个fuck22函数,打印fuck22dir3/ 子包__init__.pyfuck31.py 里面有一个fuck31函数,打印fuck31fuck32.py 里面有一个fuck32函数,打印fuck32'''###############在test.py文件中,绝对导入,from dir1.fuck11 import fuck11from dir1.dir2.fuck21 import fuck21fuck11() #输出fuck11fuck21() #输出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模块。
