[Python]-10-模块与包

引言

这篇文章介绍python中模块和包的概念。

文章目录

0×1.如何导入模块

简单的讲,模块就是可以扩展python功能的一些对象的集合,可以是类,方法,或者简单的数值对象,他们被存放在一个或多个单独的文件中,python安装后自带了大量的模块文件,我们也可以自己创建模块放入系统对应的目录中实现调用。

以ubuntu系统为例,存在与sys.path列表中的py文件,都可以被当做模块调用,不同的系统对应的位置可能不同,但都能通过下面的命令查看到:

					#在idle中查看python包含了哪些目录,在这些目录下的模块文件都能被识别和调用,sys.path实际上是一个内置的列表,我们可以使用append或extend方法将我们需要包含的目录添加到其中,这样python就能够调用我们设定的目录中的模块文件了,在这个列表中的第一个元素(本例为空字符),代表当前目录,即模块文件和调用它的文件在同一个目录中就能够实现调用,当在不同的目录中启动py程序的时候,这个元素会被py程序所在目录路径所替换
					>>> import sys
					>>> print(sys.path)
					['', '/home/qing', '/usr/bin', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']

					#手动添加一个目录,操作方法和列表一样,这里不再赘述
					>>> sys.path.append("/home/qing/test")
					>>> print(sys.path)
					['', '/home/qing', '/usr/bin', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages', '/home/qing/test']
					

可能大家已经注意到,在上面的实例中使用了一个import关键词,这个关键词可以用来调用模块和包,而sys正是python自带的模块之一(因为python内置的模块使用 c语言写的,所以系统中并没有sys.py文件),这个文件中包含一个path列表对象;我们自己创建的模块可以是一个.py后缀的python脚本文件,在导入模块的时候,不需要添加py后缀,如果熟悉HTML中css文件的导入概念,import的作用与HTML头部head标签中使用link标签将css文件导入HTML文档类似,请看下面的实例:

					#根据上面的解释,现在我们在同一个目录中创建两个py文件,一个为模块文件,一个用来调用这个模块

					#模块文件m1.py,包含两个空类,仅完成简单的初始化操作
					#!/usr/bin/env python3
					#coding=utf-8
					######
					class One:

					    #------
					    def __init__(self,items=[]):
					        """初始化列表"""
					        self.items=items
					 
					######
					class Two:

					    #------
					    def __init__(self,items={}):
					        """初始化字典"""
					        self.dect=items
					
					#调用文件test1.py与m1.py在同一个目录中
					#!/usr/bin/env python3
					#coding=utf-8
					#通过m1.py的文件名,就能直接调用这个模块文件
					import m1
					
					#lst是m1模块中One类的一个实例对象,dect是m1中Two类的实例对象
					lst=m1.One()
					dect=m1.Two()
					print(lst.items,dect.dect)
					
					#程序输出
					[] {}
					

除了上面这种导入方式外,还可以使用from...import语句来实现导入,请看下面的实例:

					#修改test1.py文件如下
					#!/usr/bin/env python3
					#这句话的意思是,从m1模块文件中导入Two这个对象(即Two类)
					from m1 import Two
					
					#这种导入方式在实例化的时候,不需要写模块名称,能够直接使用对象名称,但我们除了能够访问Two类外,不能访问m1模块中其他的类,例如One
					dect=Two()

					#除此之外,还有一种更有趣的导入方法,修改test1.py文件如下
					#!/usr/bin/env python3
					#"星号"告诉python解释器,导入m1模块中所有的对象,在本例中相当于将One和Two这两个类导入到当前作用域,
					from m1 import *
					
					#注意直接导入模块名称,和使用from导入某个或多个模块对象时,实例化对象语法上的区别,前者需要使用模块名称,后者则不需要
					x=One()
					y=Two()
					

在实际环境中,"from m1 import *"这种语法都是配合模块的"__all__"列表来实现导入的,请看下面的实例:

					#在m1.py文件头部添加一个"__all__"列表
					#!/usr/bin/env python3
					__all__=["One"]

					#test1.py文件修改如下
					#!/usr/bin/env python3
					from m1 import *

					#现在,在test1.py文件中,只能实例化m1.py文件头"__all__"列表中包含的那些对象,如果此时初始化一个Two()对象则会报错,使用这种方法,可以向用户开放模块中的可见对象,而一些内部对象则不会被包含在"__all__"列表中
					x=One()
					

from这种设计的好处是,当某个模块中包含多层类和方法的时候,我们需要访问某个方法可能需要这样写"class1.class2.sub1.sub2.x()",但如果我们只想访问x()而不想添加冗长的前缀,就可以使用"from class1.class2.sub1.sub2 import x",这样我们实例化的时候,只需要输入x()就能访问到模块中这个方法了。

说到模块就不得不说一下python一个特殊的变量"__name__",有时候我们编写了一个模块,在测试的时候,直接运行模块时,模块内部的一些方法不会被执行,这时候就可以用到变量"__name__"来主动的调用模块中的一些方法,请看下面的实例:

					#假如我们编写了下面这个helloworld.py模块,模块所有代码之前的第一个字符串是模块的说明文档,__author__变量后面是这个模块的作者名称,这些都是装饰性的语句可以不写
					#!/usr/bin/env python
					#coding=utf-8
					"helloworld.py模块"  #模块说明
					__author__="www.qingsword.com" #模块作者
					
					#打印出当前__name__变量的值
					print("__name__ is",__name__)
					def test_m():
					    print("Hello World")

					#如果__name__变量的值是__main__调用test_m()方法
					if __name__=="__main__":
					    test_m()

 					#直接执行这个模块,将会打印出下面的内容
 					__name__ is __main__
					Hello World

					#但如果我们现在使用另外一个文件导入这个模块
					import helloworld

					#执行import语句后,只得到了下面这一句
					__name__ is helloworld

					#由此我们得到两个重要的结论:
					#如果模块是被导入,__name__的值为模块名字
					#如果模块是被直接执行,__name__的值为"__main__"

					#这样设计的好处显而易见,当我们测试模块时直接运行模块代码__name__的值为"__main__",通过if语句判断可以调用我们需要调用的函数,如果是其他文件调用这个模块,那么__name__的值为模块名字,if判断失败,将不会直接调用模块中如何方法,如果需要调用,要使用方法名称,在导入模块的文件中打印出__name__变量,程序的流程就会一目了然
					#!/usr/bin/env python
					#coding=utf-8
					import helloworld
					helloworld.test_m()
					print("__name__ is",__name__)

					#程序输出,第一个__name__输出的是模块的名称(这是在import导入helloworld模块时,模块中的print的输出),第二个__name__输出的是当前的文件的名称,所有被直接运行的py文件的__name__变量值都是"__main__"
					__name__ is helloworld
					Hello World
					__name__ is __main__
					

0×2.安装第三方模块

除了能创建自己的模块外,python提供了大量的第三方模块,这些模块都各有功能,为程序开发节约了不少时间,ubuntu中安装第三方模块的方法非常简单,我只需要知道模块名称,就能够使用pip或pip3轻松的安装他们,下面用Pillow图形库举例,打开终端,输入下面的命令安装Pillow图形库:

					#如果使用的是python3,对应的第三方模块安装命令就是pip3,如果是python2,那么就是pip
					www@qingsword.com:~$ sudo pip3 install Pillow
					

需要什么模块可以先去python第三方模块官方网站"pypi.python.org"查找模块名,然后使用上面的方法安装他们。

0×3.如何导入包

模块只是一个单独的文件,而"包"可以是多个模块文件的集合,python中的"包"是以文件夹的形式存在的,python区分一个文件夹是"包"还是普通文件夹,主要搜索文件夹中是否存在"__init__.py"文件,如果有,则判断这个文件夹为"包",请看下面的实例:

					#创建一个pack1文件夹,在其中创建一个"__init__.py"文件,并在其中创建两个模块文件m1.py,m2.py,将这个文件夹和需要调用它的文件放在同一个目录中

					#m1.py文件内容,创建两个空类如下
					#!/usr/bin/env python3
					######
					class m1_class1:
					    #------
					    def __init__(self,items=[]):
					        self.lst=items

					######
					class m1_class2:
					    #------
					    def __init__(self,items={}):
					        self.dect=items

					#m2.py文件内容
					#!/usr/bin/env python3
					######
					class m2_class1:
					    #------
					    def __init__(self,items=[]):
					        self.lst=items

					######
					class m2_class2:
					    #------
					    def __init__(self,items={}):
					        self.dect=items

					#在python3规范中,现在已经可以使用py脚本访问这个包了,尽管"__init__.py"文件还是空的,只需要将包文件夹和想要访问这个包的脚本文件放在同一个目录中,我们就可以像导入模块那样来导入包中的模块,创建一个文件test2.py,将它和part1包放在同一个目录中,输入下面的内容
					#!/usr/bin/env python
					#coding=utf-8
					#导入pack1包中的m1和m2模块
					import pack1.m1,pack1.m2

					#分别实例化这两个模块中的类
					p1=pack1.m1.m1_class1()
					p2=pack1.m2.m2_class2()
					print(p1.lst,p2.dect)

					#程序输出
					[] {}
					

同模块导入一样,如果我们不希望包中的所有模块都被访问到,这时就可以利用包目录中的"__init__.py"文件,在这个文件中输入下面的内容

					#给"__init__.py"文件添加下面的内容
					__all__=["m1"]

					#修改test2.py文件的导入方式,使用from
					#!/usr/bin/env python
					#coding=utf-8
					#这条语句将搜索pack1包中的"__init__.py"文件的__all__列表,并且仅加载列表中列出的模块,所以在这个实例中,test2.py文件将不能访问m2模块中的内容,除非使用import导入,或将m2添加到__all__列表中
					from pack1 import *

					#与模块的from相似,使用这种方法导入的包文件,实例化时不需要添加包的顶级目录名称
					p1=m1.m1_class1()