模块和包 ====================================== python里用模块和包组织代码,模块就是一个个以 ``.py`` 为后缀的文件,包就是一个个带有 ``__init__.py`` 文件的文件夹。 怎么理解模块 -------------------------------------- 可以把模块理解成一个日记本,不同的日记本里都可以出现6月6号的日记,但是因为分属于不同的日记本,所以引用的时候不会出错,比如我们可以描述为A日记本某日的日记,B日记本某日的日记 定义、使用模块 --------------------------------------- 新建一个以 ``.py`` 结尾的文件,就是新建了一个模块,大家新建一个 ``a.py`` 文件,然后输入以下内容:: # coding=utf-8 num = 1 def demo(): print('im in a.py') 使用模块有如下三种方式,第一种:: from a import * 这种方式从字面理解是从a模块中导入所有内容(\*是所有的意思),然后就可以使用模块中的变量和函数了,如新建一个 ``b.py`` ,然后输入以下内容 :: from a import * print(num) demo() 看,在b模块使用a模块的变量和函数,就好像在a块中一样,但这种方式存在一个严重问题,但a模块中变量非常多,如果全部导入会污染b模块的命名空间,如,b里也有一个变量叫num,如果导入语句出现在num定义后,则会出现变量被覆盖的情况,所以非常不推荐这种方法。 第二种:: import a 这种方式是非常好的,导入模块对象,然后使用的时候可以通过 ``点号`` 取值,即 ``a.num`` 、 ``a.demo`` 这样子,这样即可以知道这些变量和函数是a模块里的,也不会污染b的命名空间。 第三种:: from a import num, demo 第三种方法看起来和第一种很相似,只是把 ``*`` 换成了具体的变量名,虽说原理相似,但这种按需导入的方式,即使变量名有冲突,也可以很快的找出来,使用方式同第一种。 __name__是什么? --------------------------------------- 经常在模块里看到如下语句:: if __name__ == '__main__': xxxx 那么 ``__name__`` 是什么? ``__main__`` 又是什么呢?故名思意, ``__name`` 是名字,模块的名字,比如:: import a print(a.__name__) 大家可以看到输出为 ``a`` 也就是模块的名称,但是在a模块里执行 ``print(__name__)`` 会是什么呢?结果是 ``__main__`` ,也就是说,当模块被当做运行主体时, ``__name__`` 的值是 ``__main__`` ,但被导入的时候,值为模块名。所以可以用 ``if __name__ == '__main__':xxx`` 去判断只在运行该模块运行时执行下面的语句,被导入时不执行。 引用标准库里的模块 --------------------------------------- python标准库里有很多现在的模块可以使用,如果 ``sys`` 、 ``time`` 、 ``datetime`` 等等,使用标准库里的模块与我们写的方式是一样的,如:: # coding=utf-8 import sys import time import datetime print(sys.path) print(time.time()) print(datetime.datetime.now()) 标准库里的模块非常之多,覆盖数据结构、文件系统、字符处理、时间日期等等, 大家可以看一下这个目录,https://docs.python.org/2/library/index.html 什么是包? --------------------------------------- 上面我们把模块比喻成了日记本,但在我们可以把包比喻成盒子,盒子里可以放日记本,每个盒子都有自己的名字,如 ``box_a`` 、 ``box_b`` ,包在实现体现就是文件夹,新建一个文件夹,然后在里面放一个名为 ``__init__.py`` 的文件(空的也可以,但名字要对),这时这外文件夹也被称为包。包是用来组织模块的,以用来避免模块名重复的问题,同时也可以把功能类似的模块放到一个包里,即可以起到分类的作用。 怎么使用包 --------------------------------------- 使用包非常简单,就跟模块差不多,只是要加上包名,如 ``from box_a.a import num`` ,先是包名,然后是点号,通过点号索引下面的模块。 嵌套包 --------------------------------------- 包内不仅可以模块,还可以再放入包,思考如下结构:: └── outer (外面的包) ├── __init__.py ├── a.py ├── b.py └── inner (里面的包) ├── __init__.py └── c.py 2 directories, 5 files 怎么导入c模块呢?同样可以使用点号去索引里面的包,如:: from outer.inner import c import是怎么查找包或模块的呢? --------------------------------------- 比如说,你有两个包,一个在C盘,一个在D盘,两个包名字一样,那么导入的时候,是导入哪一个呢?答案是可能都导入不了,python是按照 ``sys.path`` 里的路径去查找包或模块的,该列表的内容大致如下:: ['', '/usr/local/Cellar/pyenv/1.0.10/versions/2.7.13/bin', '/usr/local/opt/pyenv/versions/2.7.13/lib/python27.zip', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/plat-darwin', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/plat-mac', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/plat-mac/lib-scriptpackages', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/lib-tk', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/lib-old', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/lib-dynload', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/site-packages', '/usr/local/opt/pyenv/versions/2.7.13/lib/python2.7/site-packages/IPython/extensions', ] 大家可能跟我的不太一样,但是类似,在这个列表里,第一个元素是空字符串,后面是一些路径,路径就不用解释了,这个空字符串是代表当前目录,也就是你所在的目录。当在当前目录找不到时,会按着这个列表顺序去下个路径找,以此类推,最后还找不到,就会报错。回到正题,我们怎么运行例如 ``c:\outer`` 包呢? **第一种方式** 我们看一下,outer包在c盘下,也就是说c盘在查找路径里,我们就可以找到该包,所以在需要引用outer包的脚本里加上 ``sys.path.append(r'c:/')`` ,这种修改只是临时性的,脚本执行完后,又会恢复原状。 **第二种方式** 除了修改查找路径,我们还可以在当前路径上做文章,我们去包路径下执行不就得了?因为此时,当前路径就是包所在的路径了,所以自然可以找到包。