我们现在有了2个数学模块,想把它们放到mymath目录(文件夹)里,就成了一个“包”,随时可以引用:
。在工作目录建一个文本文件work.py,用idle打开:
。运行这个文件:
。
导入模块测试:
,可以在模块前增加“mymath.”就行了。如果工作目录不同,这个方法需要把要用的模块文件夹拷贝到工作目录下。这很不方便,也容易产生版本混乱。有没有只放在一个地方,不管是什么工作目录都可以使用的方法呢?
有,就是使用内置sys模块中的path对象的append方法把“mymath”目录所在的目录绝对路径加进去。先在d盘建目录mypython,然后把mymath剪切过去:
。重启work.py文件:
。测试引入模块:
,系统没找到模块。怎么办呢?
把包所在的目录加到sys.path中:
,
成功了!
如果想把mymath模块细分到school类别中,对目录结构进行修改:
。
导入测试:
。
绝对路径导入模块总结:把模块的全路径分为两部分,前一部分用sys.path.append加入sys.path中,另一部分作为被导入模块的前缀。
用import导入单个模块测试:
,
通过import语句导入模块后,要使用不可以直接用模块名称,要连全部前缀都要直接写在代码中。这很不方便,有没有不用写前缀的方法呢?
有,就用“from 模块所在的目录 import 模块名称”句型:
。
在这一句语句中,可以同时导入多个模块:
。
如果想把目录中所有的模块都导入,能否使用通配符呢?测试一下:
,
可见,程序根本就没导入模块,这是为什么呢?
原来,包中可以有一个特殊的文件__init__.py,在mymath中加入这个文件:
,然后再试试:
,
还是不行。
原来要使用这句型的通配符,就需要在__init__.py文件中的__all__列表明确写入通配情况下导入的模块:
。
现在测试一下:
,
可见,"from 文件夹 import * "只导入__init__.py中__all__列表中的模块,如果__all__列表为空或没有,或者没有__init__.py文件,这个语句貌似啥都不做。
模块引用当前目录和子目录中的模块,上面都写明了;如果是子目录中的模块要引用父目录中的模块,那应该怎样呢?在各级目录中添加一个测试模块如下:
。尝试运行最后的模块:
,
一个点号(.) 表示当前目录,最为main模块使用时出错;注释掉:
,
然后执行:
,
两点表示父一层目录,主模块中也不允许;注释掉后:
,
执行:
,
三点表示父二层目录,也不行。恢复被注释掉的代码行。
运行mypython里的测试模块打开新的idle界面:
。
当执行导入school.mymath.test模块时,这个模块又导入了schooltest模块,执行schooltest模块的“from mymath import zhengshiyunsuan”出错。尝试直接导入看看:
,
情况一样。采用点号改写schooltest.py:
,
直接运行出错,在直接导入看看:
,
成功了。再测试导入school.mymath.test模块:
,
mypython目录是模块开始,本身不是一个包,所以出现了包穿透的错误。启动新idle,测试:
,
mypythontest.py中未使用相对目录,所以出错,修正:
,
再次测试:
。
成功了!
旁支目录有会怎样,建一个旁支目录中的模块:
,
测试一下:
,
父一层旁支在最前加两点(..),父二层加三点(...),如此类推。
总结:(1)sys.path.append(“包的存放目录”)中的“包的存放目录”不能是包的根目录,也就是说这个目录下的子目录才是各个包的根目录。这样相对目录不能指向“包的存放目录”;(2)这些存放了模块的目录(文件夹)就是包,相对位置表示方法:一小点(.)表示当前包,二小点(..)表示父一层包,三小点(...)表示父二层包,如此类推;(3)主模块(运行时__name__ = "__main__")的import不可以使用小点相对位置,一定要用sys.path.append(“包的存放目录”),import时最前无小点(.);(4)非主模块(在主模块或其他模块通过import导入的模块)一定要使用小点(.)相对位置;(5)使用"from 包 import *"语句时,只有在这个包中定义了__init__.py文件,并且文件中定义了__all__列表,这个语句就导入__all__列表中的模块,否则貌似啥都不做;(6)使用"from 模块 import *"语句时,就不受__init__.py文件的限制,把模块中的公共命名全导入当前命名空间中。
练习题:把本课的测试自行测试一次,如果有疑问也可以自行设计测试。
学Python第二阶段到此结束。