模块:宏伟蓝图
-
每一个文件都是一个模块,并且模块导入其他模块之后就可以使用导入模块定义的变量名。
import使客户端以一个整体获取一个模块
from允许客户端从一个模块文件中获取特定的变量名
imp.reload在不中止python程序的情况下,提供了一种载入模块文件代码的方法 -
导入是运行时的运算,程序第一次导入指定文件时,会执行三个步骤:找到模块文件、编译成位码、执行模块代码来创建其所定义的对象。
模块代码编写基础
-
就像def一样,import和from都是可执行语句,而不是编译期间的声明,而且他们可以嵌套在if测试中,出现在函数def之中等,直到程序执行时,才会进行解析。被导入的模块和变量名直到他们对应的import或from语句执行后,才可以使用。就像def一样,import和from都是隐性的赋值语句
-
以from复制的变量名会变成对共享对象的引用,对已取出的变量名重新赋值,对于其复制之处的模块并没有影响,但是修改一个可变对象,则会影响导入的模块内的对象。为了实际修改另一个文件中的全局变量名,必须使用import
#Del.py
print('Del.py')
x = 1
y = [0, 1]
#Test.py
from Del import x, y
import Del
print('Main:Before Change', x, y)
print('Del:Before Change', Del.x, Del.y)
x = 'szn'
y[0] = 'szn'
print('Main:After Change', x, y)
print('Del:After Change', Del.x, Del.y)
Del.x = "szn"
print('Deal:Use Import Change:', x)
#Test.py输出结果:
Del.py
Main:Before Change 1 [0, 1]
Del:Before Change 1 [0, 1]
Main:After Change szn ['szn', 1]
Del:After Change 1 ['szn', 1]
Deal:Use Import Change: szn
>>> x, y = 1, [0, 1]
>>> def Fun():
a = x
b = y
a = 'szn'
b[0] = 'szn'
>>> Fun()
>>> x, y
(1, ['szn', 1])
- from只是把变量名从一个模块复制到另一个模块,并不会对模块名本身进行赋值
from moudle import name1, name2
import moudle
name1 = moudle.name1
name2 = moudle.name2
del moudle
#以上两段代码从概念上说,是一致的
from Moudle import * #导出Moudle的所有属性
-
在模块文件顶层,每一个赋值了的变量名都会成为该模块的属性
-
reload与import和from不同,他是一个函数而非语句。传给reload的是已经存在的模块对象,而非变量名
reload会在模块当前命名空间内执行模块文件的新代码
文件中顶层赋值语句回事的变量名换成新值
reload会影响所有使用了import读取了模块的客户端
reload只会对以后使用from的客户端造成影响,之前使用from读取的属性的客户端不受影响
#Del.py 修改前
print('Del.py')
x = 1
y = [0, 1]
#Del.py 在执行time.sleep(10)修改后
print('Del.py')
x = 123
y = [0, 123]
#Test.py
from imp import reload
import time
from Del import x, y
import Del
print('Use From Before Reload:',x, y)
print('Use Import Before Reload:',Del.x, Del.y)
time.sleep(10)
reload(Del)
print('Use From After Reload:',x, y)
print('Use Import After Reload:',Del.x, Del.y)
#输出
Del.py
Use From Before Reload: 1 [0, 1]
Use Import Before Reload: 1 [0, 1]
Del.py
Use From After Reload: 1 [0, 1]
Use Import After Reload: 123 [0, 123]
模块包
- 导入可以指定目录路径,python代码的目录称为包,因此,这类导入就称为包导入。包导入路径的最左边的部分仍是sys.path模块搜索路径中的一个目录
- 包导入语句的路径中的每个目录内都必须有__init__.py这个文件。首次导入某个目录时,会自动执行该目录下的__init__.py文件中的所有代码。例如
import dir1.dir2.mod
,表达式dir1.dir2
会返回一个模块对象,而此对象的命名空间包含了dir2的__init__.py所赋值的所有变量名。可以在__init.py__使用__all__列表来定义目录以from*语句导入时,需要导出什么
#文件层级
'''
Test.py
dir1
__init__.py
dir2
__init__.py
Test.py
'''
#Test.py
import dir1.dir2.Test
print(dir1.x)
#dir1\__init__.py
print('dir1.__init__')
x = 'dir1'
#dir1\dir2\__init__.py
print('dir2.__init__')
y = 'dir2'
#dir1\dir2\Test.py
print('Test.py')
z = 'Test'
#输出
dir1.__init__
dir2.__init__
Test.py
dir1
- 在包自身的内部,包文件的导入可以使用和外部导入相同的路径语法,但是也可以使用特殊的包内搜索规则简化导入语句。
- python3.0模块导入搜索路径语义默认的跳过包自己的目录,导入只是检索搜索路径的其他组件,这叫做绝对导入。比如在包文件中:
import Test
不会搜索包路径下的Test.py,而会搜索sys.path中包含的路径下的Test文件- python扩展了from的语法,允许显示的要求导入只搜索包的目录,这叫做相对导入,如下:
from . import Test #Test.py位于当前文件的相同包路径下
from . Test import v #导出处于当前文件的相同包路径下的Test.py中的v
from .. import Test #Test.py位于当前文件上层目录下
from ... import Test #Test.py位于当前文件上上层目录下
#以此类推
注意点:
相对导入适用于只在包内导入
相对导入只适用于from语句
- 利用as来使用别名
import dir1.dir2.dir3.dir4.Szn as Szn
import MoudlName as MName
from MoudleName import Name as N
模块高级话题
-
from XXX import*
细节
- 把下划线放在变量名前,可以防止客户端使用
from XXX import*
语句导出模块名时,把其中的那些变量名复制出去。下划线不是私有声明,还是可以通过其他导入形式看见并修改这类变量名。- 在模块顶层把变量名的字符串列表赋值给变量__all__,来指定
from XXX import*
时导出的变量- python会首先寻找模块内的__all__,若未定义则
from XXX import*
会复制出开头没有下划线的所有变量名
-
每个模块都有个名为
__name__
的内置属性,python会自动设置该属性:如果文件是以顶层程序文件执行,则此属性被设置为'__main__'
。如果文件被导入,则此属性被设置为客户端所了解的模块名。结果就是模块可以检测自己的__name__
,来确定自己是在执行还是被导入 -
通过修改
sys.path
列表,来修改当前程序的模块搜索路径,此修改在程序结束后不会保存下来 -
getattr可以通过字符串名来取出属性
#Szn.py
s = 'szn'
#Test.py
import Szn
print(getattr(Szn, 's'))
#输出
szn
- eval(str)函数将字符串str当成有效Python表达式来求值,并返回计算结果。
exec(str)函数将字符串str当成有效的Python表达式来执行,不返回计算结果
>>> exec('1 + 2')
>>> eval('1 + 2')
3
-
__import__
可以通过字符串导入模块
#Szn.py
print('Szn')
s = 's'
#Test.py
s = __import__('Szn')
print(s.s)
#输出
Szn
s
网友评论