一、简介
1、模块(module):根据python官方的解释,所谓模块就是一个.py文件,用来存放变量,方法的文件,便于在其他python文件中导入(通过import或from);
2、包(package): 包是更大的组织单位,用来组织区别管理多个模块文件;引用官方的说法:"假设你想要设计一个模块(包)来统一处理声音文件和声音数据的集合。有许多不同的声音文件格式(例:.wav,.aiff,.au,.mp3等),因此您可能需要创建和维护不断增长的模块集合,以便在各种文件格式之间进行转换。对于声音数据,您可能还需要执行许多不同的操作(例如混音,添加回声,应用均衡器功能,创建仿真立体声效果),因此除此之外,您还将编写永无止境的模块流这些操作。此时就可以有一个可能的结构(用分层文件系统来表示)"
3、import 用来导入模块(单文件或包中);from 用于从模块(单文件或包中的文件模块)中导入方法(全部或部分)也可用于as 重命名导入的方法名.
包的好处:不管是通过import 还是from 模块(方法)都是通过sys.path中的搜索路径去查找,或程序运行的当前目录.而这种搜索是线性的,所以,如果有两个模块名是一样的,就无法同时导入这两个同名模块中的方法.
了解了包与模块以及import 与from使用区别限制。对我们看源代码项目很有帮助,也便于我们自己组织
项目代码。
百说不如一练,下面通过实例来演示包和模块在使用import和from导入(引用)时的区别.
二、测试环境构建
1、首先我们的实验环境目录如下:
modesdir #顶层目录
-web #web包
-web2 #web2包
-__init__.py #web2包中的__init__.py文件 (python包中必须有__init__.py文件作用后面说)
-hello.py #web2中的hello文件(模块)
-__init__.py #web包中的__init__.py文件(模块)
-logger.py #web包中的logger.py文件(模块)
-webtest.py #web包中的webtest.py模块
-conf #conf包
-__init__.py #conf包中的__init__.py文件
-webtest.py #模块
-bin.py
-calculate.py
注:上图中的模块下以f开头的是模块文件中函数
2、各包(模块中的代码)
#cat calculate.py
1
2
3
4
5
6
7
8
9
10
11
|
#coding:utf-8 print ( "OK" )
_z = "Zz"
x = 3
def add(x,y):
return x + y
def sub(x,y):
return x - y
def chen(x,y):
print ( "from mod" )
return x * y
|
#cat web/__init__.py
1
2
|
#coding:utf-8 print ( "in web1" )
|
#cat web/logger.py
1
2
3
|
#coding:utf-8 def logger():
print ( "logging." )
|
#cat web/webtest.py
1
2
3
|
#coding:utf-8 def webTest():
print ( "This is web2 test." )
|
#cat web/web2/__init__.py
1
2
|
#coding:utf-8 print ( "in web2" )
|
#cat web/web2/hello.py
1
2
3
|
#coding:utf-8 def hi():
print ( "Hello world!" )
|
#cat conf/webtest.py
1
2
|
def MyConf():
print ( "my conf file." )
|
三、针对模块和包中的模块import
这里以modesdir下的bin.py为入口测试主程序
来做以下测试:
1、导入calculate.py单模块文件
1
2
3
|
import calculate
result = calculate.add( 1 , 2 )
print (result)
|
结果如下:
注意上面的OK输出 ,说明import时执行了模块中的代码(从上到下)。
2、导入web包中的模块
1
2
|
import web.logger
web.logger.logger() |
运行结果如下:
输出多了一个in web1 很明显这是web包下的__init__.py被执行。那么先插一句:
__init__.py :用来给包做一些初始化的工作。可以为空,但必须要有,主要防止区别同名的目录,官方文档中说可以通过在__init__.py中__all__ = [ ] 中放入模块名。这样from “包” import * 时可看见的
模块就在__all__中列出的,否则模块不可见。所以这里输出了in web1内容.
3、导入web.web2中的模块
1
2
|
import web.web2.hello
web.web2.hello.hi() |
运行结果如图:
这里由于导入了web.web2两个包 所以出现 in web1 in web2内容,可以看出__init__.py作用了吗?
测试,所以可以删除。
如果直接导入包(或包下的包)是什么情况 ?
4、导入web.web2
1
2
|
import web.web2
web.web2.hello.hi() |
运行如图:
出错。找不到。
结论:
import 导入可以是“ 包.模块 或 包.N包.包.模块 或直接 模块”(当前目录或sys.path环境变量中的)不能是只有包没有模块,换句话说必须以模块结尾,不管是包中的还是单独模块文件调用时
调用时以"[包.]模块.方法(“参数”)" 这里包可选。此例中import web.web2.hello 即可.
四、from的用法
1、从calculate中导入add函数方法
1
2
|
from calculate import add
print (add( 1 , 2 ))
|
运行结果如图:
运行结果与上节三 1 下的import调用结果一致。不过调用方式不一样,这里直接调用原模块中的文件名。
2、从web包中导入logger模块中的logger函数方法
1
2
|
from web.logger import logger
logger() |
运行如图:
和上节中三 2中import web.logger.logger()执行一致。
3、从web(包).web2(包).hello模块中导入hi方法
1
2
|
from web.web2.hello import hi
hi() |
运行结果:
同样和上节中的3 web.web2.hello.hi()执行结果致。
4、from calculate import *时
1
2
|
from calculate import * print(_z) |
运行结果:
此时_z变量没有找到;另外双下划线__开头(非__双下划线结尾)变量的也是无法找到!
5、__all__ = [] 在from 包 import *时
1
2
3
|
from web import *
logger.logger() webtest.webTest() |
运行结果:
上图可以看出在from web import *时 由于__all__中的限制 没有列出webtest模块。所以这里
logger.logger()调用成功,输出logging.而webtest模块提示没有定义 ,找不到。
6、不同包的模块名相同时导入引用
从conf包中导入webtest.py模块并运行MyConf方法
从web包中导入 webtest.py模块并运行webTest方法
1
2
3
4
|
from web import webtest
webtest.webTest() from conf import webtest
webtest.MyConf() |
运行结果如下:
五、总结
通过以上模拟包和模块,包与包中模块并从主入口bin.py程序入口进行测试 。引入包及包中的模块,单独引用模块中的方法,引用不同包中同名模块等;测试总结如下("[ ]"中括号中的表示可选):
同名模块可以存在于不同的包中;
import使用方法:
import 模块 [as 别名模块]
import 包.[N包].模块;
import 导入 最后一个必须是模块,而不能以包结尾.例:三节第4个例子.
from使用方法:
from 包.[..包] import 模块
或
from 包.模块 import 方法
或
from 模块 import 方法。
from引用虽然灵活,可以直接from导入模块或方法,但有可能破坏现有的命名空间中的同名方法。且from 包 import *时,受__init__.py中的__all__影响,没有列出来的模块是没法导入引用的。而from 模块 import *时,以下线线_开头的私有变量受到影响没法引用。另外from还可以导入 模块或方法时通过as 得命名模块或方法名.
以上测试在pycharm环境中 2.x及3.x均可,以上代码在3.5.2下通过。