一、简介

1、模块(module):根据python官方的解释,所谓模块就是一个.py文件,用来存放变量,方法的文件,便于在其他python文件中导入(通过import或from);


2包(package): 包是更大的组织单位,用来组织区别管理多个模块文件;引用官方的说法:"假设你想要设计一个模块(包)来统一处理声音文件和声音数据的集合。有许多不同的声音文件格式(例:.wav,.aiff,.au,.mp3等),因此您可能需要创建和维护不断增长的模块集合,以便在各种文件格式之间进行转换。对于声音数据,您可能还需要执行许多不同的操作(例如混音,添加回声,应用均衡器功能,创建仿真立体声效果),因此除此之外,您还将编写永无止境的模块流这些操作。此时就可以有一个可能的结构(用分层文件系统来表示)"


3import 用来导入模块(单文件或包中);from 用于从模块(单文件或包中的文件模块)中导入方法(全部或部分)也可用于as 重命名导入的方法名.

包的好处:不管是通过import 还是from 模块(方法)都是通过sys.path中的搜索路径去查找,或程序运行的当前目录.而这种搜索是线性的,所以,如果有两个模块名是一样的,就无法同时导入这两个同名模块中的方法.

了解了包与模块以及import 与from使用区别限制。对我们看源代码项目很有帮助,也便于我们自己组织

项目代码。

百说不如一练,下面通过实例来演示包和模块在使用import和from导入(引用)时的区别.


二、测试环境构建

1首先我们的实验环境目录如下:

3b7196e59df0f5f9b24d14ff74fc6983.png-wh_

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

#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

#coding:utf-8
print("in web1")

#cat web/logger.py

#coding:utf-8
def logger():
    print("logging.")


#cat web/webtest.py

#coding:utf-8
def webTest():
    print("This is web2 test.")

#cat web/web2/__init__.py

#coding:utf-8
print("in web2")

#cat web/web2/hello.py

#coding:utf-8
def hi():
    print("Hello world!")

#cat  conf/webtest.py

def MyConf():
    print("my conf file.")


三、针对模块和包中的模块import

这里以modesdir下的bin.py为入口测试主程序

来做以下测试:

1、导入calculate.py单模块文件

 import calculate
 result = calculate.add(1,2)
 print(result)

结果如下:

00f62e3c28fbda5c192795acd8190379.png-wh_

注意上面的OK输出 ,说明import时执行了模块中的代码(从上到下)。

2、导入web包中的模块

import web.logger
web.logger.logger()

运行结果如下:

034a9e0f5bd6fedc66c0800ada46e26b.png-wh_

输出多了一个in web1  很明显这是web包下的__init__.py被执行。那么先插一句:

__init__.py :用来给包做一些初始化的工作。可以为空,但必须要有,主要防止区别同名的目录,官方文档中说可以通过在__init__.py中__all__ = [ ] 中放入模块名。这样from  “包”   import * 时可看见的

模块就在__all__中列出的,否则模块不可见。所以这里输出了in web1内容.


3、导入web.web2中的模块

import web.web2.hello
web.web2.hello.hi()

运行结果如图:

58637c8bc7622470b0275a05a5e34ef4.png-wh_

这里由于导入了web.web2两个包 所以出现 in web1   in web2内容,可以看出__init__.py作用了吗?

测试,所以可以删除。


如果直接导入包(或包下的包)是什么情况 ?

4、导入web.web2

import web.web2
web.web2.hello.hi()

运行如图:

bfd2c2f762a85a75528e30d776571717.png-wh_

出错。找不到。

结论:

        import 导入可以是“ 包.模块 或 包.N包.包.模块 或直接  模块”(当前目录或sys.path环境变量中的)不能是只有包没有模块,换句话说必须以模块结尾,不管是包中的还是单独模块文件调用时
调用时以"[包.]模块.方法(“参数”)"   这里包可选。此例中import web.web2.hello   即可.


四、from的用法

1、从calculate中导入add函数方法

from calculate import add
print(add(1,2))

运行结果如图:

b60ff55241c649e79077755bb408db45.png-wh_

运行结果与上节三 1 下的import调用结果一致。不过调用方式不一样,这里直接调用原模块中的文件名。

2、从web包中导入logger模块中的logger函数方法

from web.logger import logger
logger()

运行如图:

b7a550b37f3459a0520c3cb17e132d58.png-wh_

和上节中三 2中import  web.logger.logger()执行一致。

3、从web(包).web2(包).hello模块中导入hi方法

from web.web2.hello import hi
hi()

运行结果:

f5b3a45fe747a885d0e2be885b6778ab.png-wh_

同样和上节中的3 web.web2.hello.hi()执行结果致。

4、from calculate import *时

from calculate import *
print(_z)

运行结果:

9eaa0400f8a675d39ebb52ed0a627f9a.png-wh_

此时_z变量没有找到;另外双下划线__开头(非__双下划线结尾)变量的也是无法找到!


5、__all__ = [] 在from 包 import *时

from web  import *
logger.logger()
webtest.webTest()

运行结果:

30865f2076a0aebb50b866c7556bd741.png-wh_

上图可以看出在from web import *时 由于__all__中的限制 没有列出webtest模块。所以这里

logger.logger()调用成功,输出logging.而webtest模块提示没有定义 ,找不到。


6、不同包的模块名相同时导入引用

从conf包中导入webtest.py模块并运行MyConf方法

从web包中导入 webtest.py模块并运行webTest方法

from web import webtest
webtest.webTest()
from conf import webtest
webtest.MyConf()

运行结果如下:

2958f67299641506e3ff669fc28f37f2.png-wh_



五、总结

       通过以上模拟包和模块,包与包中模块并从主入口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下通过。