模块是把程序代码和数据封装的Python文件,也就是说,每个以扩展名py结尾的Python源代码文件都是一个模块。每个模块文件就是一个独立的命名空间,用于封装顶层变量名;在一个模块文件的顶层定义的全部的变量名(函数名也是一个变量名),称做模块的属性。导入模块给予了对模块的全局做用域中的变量名的读取权,也就是说,在模块导入时,模块文件的全局做用域变成了模块内对象的命名空间。app
导入一个模块以后,可使用模块中定义的属性,例如,在模块moduleA中导入一个模块moduleB,那么moduleB就变成了命名空间,在moduleA中可使用moduleB中的全局变量,引用的格式是:moduleB.attribution_name。编辑器
归纳来讲,Python中的模块拥有三个大的做用:函数
通常来讲,一个Python程序结构是由一个主文件(又称为顶层文件、脚本)和多个模块构成的,其中主文件包含了程序的控制流程,也就是启动以后可以运行整个程序的文件,而模块文件是用于提供工具的库。工具
在Python中,一个文件导入了一个模块来得到该模块内定义的工具的访问权,所以,通用的Python程序的结构就是:在顶层文件中导入模块,并引用模块中的工具。spa
例如,在脚本文件main.py中导入functools模块中的reduce()函数,使用该工具函数实现列表元素的加和:命令行
from functools import reduce a=reduce((lambda x,y:x+y),range(0,5)) print(a)
定义模块,只须要使用文本编辑器,把一些Python代码输入到文本文件中,而后以".py"为扩展名名进行保存,任何此类文件都会被自动认为是Python模块。在模块顶层指定的变量名是模块的属性。注意:模块的文件名必须以扩展名 .py 结尾。code
例如,建立一个strtools模块,文件名必须是strtools.py,文件的内容是Python代码,其中append_suffix是模块的属性名,引用该属性的格式是:strtools.append_suffix(arg):orm
def append_suffix(str): return str+'- py'
导入从本质上来说,就是为了载入另外一个文件,并可以读取该文件的内容。模块的导入是由两个语句来处理:对象
import语句和from语句都会加载模块,加载的过程包括搜索、编译和执行模块文件。二者的差异在于:import语句 会读取整个模块,因此必须进行定义后才能读取它的属性;form语句直接获取模块中特定的变量名。blog
在一个导入语句中的模块名起到两个做用:识别加载的外部文件;把模块名做为命名空间,用于封装模块内的顶层变量名。在导入模块时,模块定义的对象也会在import语句执行时建立,经过module_name.attribution_name来引用模块内定义的变量名。
例如,在主文件中导入strtools模块,并使用append_suffix()函数:
import strtools mystr=strtools.append_suffix('It is a cat') print(mystr)
1,import语句
import语句使用一个变量名来引用整个模块对象,所以,必须经过模块名称来得到模块的属性:
import strtools strool.append_suffix('xx')
2,from语句
from语句把变量名复制到另外一个做用域,所以,能够直接在脚本中使用变量名,而不须要经过模块:
from strtools import append_suffix append_suffix('xx')
因为模块中的变量名可能由不少,可使用*,取得模块顶层的全部变量名,把模块顶层的变量名都复制到当前的做用域内:
from strtools import *
从技术上来讲,import和from * 语句都会使用相同的导入操做,from * 形式只是多加了步骤,把模块中全部的属性名复制到了导入的做用域以内。
3,导入只发生依次
模块会在第一次import或from时载入并执行,而且只在第一次如此。默认状况下,Python只对每一个文件作一次导入操做,以后的导入操做操做都只是取出已加载的模块对象。
4,import和from是赋值语句
import和from是可执行的语句,而不是声明语句,也就是说,被导入的模块和变量名,直到它们所对应的import或from语句执行后,才可使用。
import和from是隐式的赋值语句:
以from语句复制而来的变量名和其来源的文件之间没有联系,为了实际修改另外一个文件中的全局变量名,必须使用import语句。
例如,使用from导入变量x,修改变量不会影响模块中x的值,这是由于from语句把模块的对象复制到本地做用域的变量,因此,本地做用域对变量从新赋值,会建立一个新的对象。
from module import x,y x=1 # change the variable
可是,对可变类型对象的修改,会影响模块的对象的值,这是由于list_names支持原处修改,这跟赋值不一样:
from module import list_names list_names[0]='vic'
5,import和from的对等性
from只是把变量名从一个模块复制到另外一个模块,并不会对模块名自己进行赋值。
从概念上来说,一个像这样的from语句:
from module import name1,name2
与下面这些语句是等效的:
import module name1=module.name1 name2=module.name2 del module
就像全部的赋值语句,from语句会在导入者中建立新变量,而这些变量初始化时引用了被导入文件中的同名对象。不过,只有同名的变量名(并非全部的变量名)被赋值出来,而非模块自己,from未指定的变量名都没有复制出来。
从上文可知,模块是变量名的封装。Python会把每个.py文件看做一个模块,建立模块对象,以包含模块内所复制的全部顶层变量名,这些顶层变量名就是模块对象的属性。
1,模块语句会在首次导入时执行
模块在第一次导入时,Python都会创建空的模块对象,按照文件从头至尾的顺序,逐一执行模块内的语句。
2,顶层的赋值语句会建立为模块属性
在导入时,在模块顶层的赋值语句左侧的变量,成为模块对象的属性,赋值的变量名会存在模块的命名空间内。
3,模块的命名空间可以经过属性__dict__或dir(module)函数获取
在导入时,Python会把创建模块的命名空间的字典,经过模块对象的属性__dict__来读取,也能够经过dir(module)函数来读取。
4,模块是一个独立的做用域
模块内的命名空间是一个独立的做用域,经过点号 ( . )来引用属性,引用的格式是:object.attr_name。
从上文可知,导入只发生一次,要想重载模块,须要 调用 reload()函数。
注意,在使用reload()函数重载模块以前,模块必定是已经预先导入了。
通常的用法是:导入一个模块,在文本编辑器中修改其源代码,而后将其重载。
import module ... use module.attributes ... # now, go change the module file from imp import reload reload(module) # get the changes ... use module.attributes
当调用reload()函数时,Python会从新读取模块问价的源代码,从新执行其顶层代码,在适当的地方修改已导入的模块对象,reload()不会删除并重建模块对象。
在调用reload()函数以后,程序中任何引用该模块的对象,自动会受到重载的影响。
1,重载模块会致使模块代码的从新执行
reload()函数会使模块从新执行模块文件的新代码,从新执行模块文件的代码,会覆盖现有的命名空间,但不是把模块对象删除并进行重建。
2,模块文件中顶层的赋值语句会使得变量名从新赋值
在调用reload()函数时,赋值语句会从新执行,进而模块的顶层变量会被从新赋值,这会致使顶层变量引用的对象会从新建立。
例如,模块重载会致使顶层的def语句从新执行,对函数名进行从新赋值,这使得函数对象会被从新建立,函数名引用的对象不是模块以前的版本。
3,重载对import语句的影响
模块重载会影响全部使用import语句读取了模块的脚本,这是由于使用import语句的脚本,须要经过点号运算获取属性,在模块重载后,模块的属性变成了新值。
4,重载对from语句的影响
模块重载只会对之后使用from语句的脚本形成影响,以前使用from语句来读取属性的变量名不会受到重载的影响,其引用的是值依然是重载以前所获取的对象。
这是由于,模块重载会致使模块顶层变量的从新赋值,这使得模块顶层变量引用的对象会从新建立,模块顶层变量引用的是新对象,而在重载以前执行的from语句,变量引用的是旧版本的对象,这个旧版本的对象不会被销毁,但和重载以后的新对象不是同一个对象了。
5,重载不会传递到导入的模块
重载不会影响模块已经导入的模块,例如,若是要重载模块A,而且模块A导入模块B和C,那么重载只适用于A,而不适用于B和C。在重载模块A时,模块B和C因为已经加载了,模块A只会获取已经载入的模块B和C对象。
若是要重载已经导入的模块,那么必须显式重载这些模块:
from imp import reload # firstly reload imported modules reload(C) reload(B) # then reload the outer module reload(A)
在这一节中,咱们探索模块的使用标志,模块内变量的前向引用,和点号运算符的特性等。
1,使用模式的标志
每一个模块都有个名为__name__的内置属性,Python会自动设置该属性:
模块能够检测本身的__name__属性,以肯定本身是在执行(run)仍是导入(import)。
2,命令行参数
在Python中,sys.argv列表包含了命令行参数,它是反映在命令行上录入的单词的一个字符串列表,其中,第一项老是将要运行的脚本的名称。
import sys
3,import语句和from语句的as扩展
import语句使用as扩展,能够为模块设置别名:
from module import attr_long_name as short_name
from语句把从模块导入的变量名,复制给脚本中的不一样的变量名,当模块中的变量名和当前做用域的变量名重名时,使用as扩展,能够避免变量名冲突:
import module_long_name as short_name
4,前向引用
当模块收入导入(或重载)时,Python会从头至尾执行语句,也就是说,语句只会引用前面已经定义的变量,这就是变量的前向引用,所以,模块顶层代码的语句顺序是很是重要的。
通常来讲,前向引用只对当即执行的模块顶层代码有影响,函数能够引用任意一个模块顶层的变量名。
5,from是变量名的赋值,而import是引用对象
其实,from语句是一个普通的赋值运算,把模块内的变量名赋值给导入者的做用域内的变量名,实际上就是把变量名赋值给变量名,两个不一样做用域内的变量共享对象的引用,也就是说,一个对象的引用位于不一样的文件中。
例如,有模块mod_1,有两个属性,变量x和函数printer:
x=1 def printer():print(x)
在文件mod_2中,使用from导入模块mod_1,对变量x进行赋值,会致使变量x引用新的对象,而不是修改mod_1.py中的变量x的值:
from mod_1 import x, printer x=2 printer() # print 1
在文件mod_3中,使用import导入整个模块,当使用点号运算符修改模块内的属性时,就会修改mod_1.py中的变量的值,点号运算符把Python定向到了模块内的变量名,对变量进行修改,而不是赋值:
import mod_1 as m m.x=2 printer() # print 2
注意:点号运算符是引用变量,并修改变量的值。
6,reload()函数不会影响from导入
由于from语句在执行时会赋值变量名,因此,不会连接到变量名所在的模块。经过from语句导入的变量名就简单地变成了对象的引用。
当重载模块时,模块会从新建立对象,变量名引用新建的对象,然而位于重载以前的from引用的原始对象并不会改变,重载会影响后面的from语句。
from module import x ... from imp import reload() reload(module) #changes module in-place x #still references old object
reload()函数会影响import语句,这是由于,重载不会删除和新建模块对象,也就是说,import语句引用的模块对象不变,可是,模块对象中的属性会被删除重建。当经过点号来引用模块的对象时,object.attr 会引用模块的最新建立的变量。
import module ... from imp import reload() reload(module) #changes module in-place module.x #get current x: reflects module reloads
参考文档: