一:python
中的模块和包
模块: 如果你从 Python 解释器退出后再重新进入, 那么你之前定义的所有 (函式和变量) 都将丢失. 因此, 如果你想写一个更长的程序, 你最好离线地使用文本编辑器保存成文件,替代解释器的输入来运行. 这称作创建一个 脚本 . 当你的程序变得更长, 你可能想把它分割成几个文件以能够更简单地维护. 你也许还想在几个下同的程序里使用写过的程序, 而不用把一坨代码拷来拷去.
为此 Python 提供了方法, 能使用户把定义存放在文件里, 同时又能在脚本或交互式环境下方便的使用它们. 这样的文件称为 模块 ; 一个 模块 中的定义可以 导入(import) 到另一个模块或 主 模块 ( 主 模块是执行脚本的最上层或计算模式下的一组可访问变量的集合).
模块就是包含 Python 定义和语句的文件. 文件的名字就是这个模块名再加上 .py. 在一个模块中, 模块的名字 (一个字符串) 可以通过全局变量 __name__ 得到.
包: 包是一个有层次的文件目录结构,它定义了由n个模块或n个子包组成的python应用程序执行环境。通俗一点:包是一个包含__init__.py 文件的目录,该目录下一定得有这个__init__.py文件和其它模块或子包。
包对应于文件夹,使用包的方式跟模块也类似,唯一需要注意的是,当文件夹当作包使用时,文件夹需要包含__init__.py文件,主要是为了避免将文件夹名当作普通的字符串。__init__.py的内容可以为空,一般用来进行包的某些初始化工作或者设置__all__值,__all__是在from package-name import *这语句使用的,导出在__all__声明过的模块。
二:模块的搜索路径
python在执行import语句时,到底进行了什么操作,按照python的文档,它执行了如下操作:
第1步,创建一个新的,空的module对象(它可能包含多个module);
第2步,把这个module对象插入sys.module中
第3步,装载module的代码(如果需要,首先必须编译)
第4步,执行新的module中对应的代码。(这里提醒我们Python模块中的代码在被导入时会被执行一次,但是只有在第一次被导入时才会被执行)
第三步查找module的过程
在import的第一个阶段,主要是完成了查找要引入模块的功能,这个查找的过程如下:
检查 sys.modules (保存了之前import的类库的缓存),如果module被找到,则⾛到第二步。
检查 sys.meta_path。meta_path 是一个 list,⾥面保存着一些 finder 对象,如果找到该module的话,就会返回一个finder对象。
检查⼀些隐式的finder对象,不同的python实现有不同的隐式finder,但是都会有 sys.path_hooks, sys.path_importer_cache 以及sys.path。
抛出 ImportError。
三:导入模块 通过以下实例来讲解导入,下面是一个project的结构图:(注:以下是在自定义的包中操作)
project/
packagea/
__init__.py
a.py
packageb/
__init__.py
b.py
bb.py
main.py
1. 如果想要调用同一个包里面的其他模块,如在packageb的bb.py中调用b.py的函数,需要使用如下方式导入:
from packageb import b
import b
或者
(经过测试,这种写法在pycharm中,会提示找不到模块b,但是你可以不用管这个,实际上可以运行)
2. 如果想要在不同包中调用其他模块中的函数,如在packageb的b.py中调用packagea中a.py的函数,需要使用如下方式导入:
from packagea import a
import packagea.a`
或者
3. 如果想要在外面的main.py中调用包中的函数或模块,如在mian.py中调用packageb中b.py的函数,需要使用
from packageb import b
import packageb.b`
或者
4. 如果想要将一个包中的所有模块导入到另一个模块中,如要在main.py中导入packageb中所有的模块,需要使用:
from packageb import *
(注意:需要在packageb的__init__.py文件加入__all__=[“需要导入的模块名”])
`5. 如果使用下面的语句进行导入:
import packageb`
packageb.bb.fuc() #这个会报错
上面的这个import语句只会执行__init__.py文件,而不会导入任何模块。不过既然会执行__init__.py文件那么我们可以在改文件中来进行一些操作。如
# packageb
# __init__.py
import b,bb
注意:无论一个包的哪个部分被导入, 在文件__init__.py中的代码都会运行.这个文件的内容允许为空,不过通常情况下它用来存放包的初始化代码。导入过程遇到的所有 __init__.py文件都被运行.
四.相关笔记:
1. 相对引入:relative import 也叫作相对引入,在Python2.5及之前是默认的引入方法。它的使用方法如下:
from .string import a
from ..string import a
from ...string import a
这种引入方式使用一个点号来标识引入类库的精确位置。与linux的相对路径表示相似,一个点表示当前目录,每多一个点号则代表向上一层目录。
2. 我们来看看下面这段代码:
# test.py
def fuc():
print("in fuc")
print("in file test")
if __name__=="__main__":
fuc()
一个模块既可以当作单独的脚本执行,也可以当作模块被导入使用。当作为单独的脚本使用时,全局变量__name__被置为__main__,if条件成立,那么会执行if条件中的内容,这个作用可以用来测试脚本代码。
当作为模块被导入使用时,__name__就会被置为模块名,而根据上面第二个说明,我们知道系统会执行一次该模块的代码,此时print会输出内容,而if条件不成立就不会在被执行了。
3. 如果一个模块如果定义有列表__all__,则from module import *语句只能导入__all__列表中存在的对象。如:
# test.py
__all__ = ["fuc1","fuc2"]
def fuc1():
print("in fuc1")
def fuc2():
print("in fuc2")
def fuc3():
print("in fuc3")
此时如果在其他模块使用 from test import * ,那么只能导入fuc1 和 fuc2这两个函数。
参考:
http://docspy3zh.readthedocs.io/en/latest/tutorial/modules.html#tut-modulesasscripts
https://neo1218.github.io/python-import/
http://www.voidcn.com/blog/u010786109/article/p-3168626.html