模块


7

7.1 简介

在上一章里我们知道了如何创建和使用函数。如果你想要在其它程序中重用很多函数,那么你该如何实现呢?你可能已经猜到了,答案是使用本章要讲的模块。

模块可以让你能够有逻辑的组织你的Python代码段。通过把相关的代码分配到一个模块里能让你的代码更好用,更易懂。模块就是一个保存了Python代码的文件。模块可以定义函数,类和变量,当然模块里也能包含可执行的代码。

7.2  import语句

如果python文件中想引用另外个文件,则可以使用import语句。这里给个例子:

1) 假设我们将之前的函数getRectangleArea保存成文件MyTools.py。

defgetRectangleArea(length,breadth=2):

    return "形参里的长度是:"+str(length)+"\t形参里的宽度是"+str(breadth)+"\n当前长方形的面积是:"+str(length*breadth)

 

注:这里文件类型要是utf-8编码。

2)我们再新建个文件加MyMain.py里面的内容是调用MyTools.py里定义的getRectangleArea函数。

import MyTools

print(MyTools.getRectangleArea(breadth=3,length=8))

 

这段代码是怎么执行的呢?

首先Python遇到import会在.py文件的当前目录找MyTools.py这个文件,

当执行到下一行时先会调用MyTools.py里定义的getRectangleArea方法。

最后通过print打印出函数的返回值,也就是3*8=24。

注:这里我们调用getRectangleArea函数时需要加上MyTools.不然会函数未定义的错:

 

C:\PythonTest>python MyMain.py

Traceback (most recent call last):

  File"MyMain.py", line 2, in <module>

   print(getRectangleArea(breadth=4,length=9))

NameError: name 'getRectangleArea' is notdefined

3)我们在命令行里通过python MyMain.py来验证:

结果:

形参里的长度是:8        形参里的宽度是3

当前长方形的面积是:24

7.3 from…import 语句

该语句是允许你从模块中一个指定的部分到当前命名空间中,语法如下:

from modname import name1[, name2[, ...nameN]]

所以上一节我们可以这么写:

fromMyTools import getRectangleArea

print(getRectangleArea(breadth=4,length=9))

注:这里我们不需要再加MyTools.getRectangleArea

7.4 from…import* 语句

如果想把一个模块的所有内容都导入到当前的命名空间就可以用该语句。


7.5 定位模块

当我们导入一个模块,Python解析器对模块位置的搜索顺序是:

Ø  当前目录

Ø  PYTHONPATH下的每个目录,这里是Python的环境变量。

Ø  默认路径,如:UNIX下一般为/usr/local/lib/python/


7.6 dir函数

如果想了解一个模块定义的标识符,可以通过dir函数进行查看,这里的标识符有函数、类和变量。比如我们看系统内的sys模块,可以在python命令行里这么做:

>>>import sys

>>>dir(sys)

结果:

['__displayhook__','__doc__', '__excepthook__', '__interactivehook__', '__loade

r__', '__name__','__package__', '__spec__', '__stderr__', '__stdin__', '__stdou

t__','_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegac

ywindowsfsencoding','_getframe', '_home', '_mercurial', '_xoptions', 'api_versi

on', 'argv','base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteord

er', 'call_tracing','callstats', 'copyright', 'displayhook', 'dllhandle', 'dont

_write_bytecode','exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit',

 'flags', 'float_info', 'float_repr_style','get_asyncgen_hooks', 'get_coroutine

_wrapper','getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getf

ilesystemencodeerrors','getfilesystemencoding', 'getprofile', 'getrecursionlimi

t', 'getrefcount','getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsvers

ion', 'hash_info','hexversion', 'implementation', 'int_info', 'intern', 'is_fin

alizing', 'last_traceback','last_type', 'last_value', 'maxsize', 'maxunicode',

'meta_path','modules', 'path', 'path_hooks', 'path_importer_cache', 'platform',

 'prefix', 'ps1', 'ps2', 'set_asyncgen_hooks','set_coroutine_wrapper', 'setchec

kinterval','setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace',

'stderr', 'stdin','stdout', 'thread_info', 'version', 'version_info', 'warnopti

ons', 'winver']



看上去有点复杂,这些都是Python系统预定义的函数或者类。我们还是以求面积的函数为例来讲解下dir函数。不过在MyTools.py的getRectangleArea函数后再加个函数MyName,具体内容见下:

defgetRectangleArea(length,breadth=2):
    return "形参里的长度是:"+str(length)+"\t形参里的宽度是"+str(breadth)+"\n当前长方形的面积是:"+str(length*breadth)
defgetMyName(firstName,LastName):
    return "我的名字是"+firstName+"\t"+LastName

importMyTools
print(dir(MyTools))


结果:

我的名字是james bond

['__builtins__','__cached__', '__doc__', '__file__', '__loader__', '__name__',

'__package__','__spec__', 'getMyName','getRectangleArea']

注:这里dir查到的函数就是getMyName和getRectangleArea。

7.7 模块的__name__

上一节我们执行dir函数查找模块的标识符时会看到__name__,它是每个模块内置的属性,记录着模块的名字。所以我们在执行MyMain.py时会有这样的结果:

MyMain.py文件内容:

importMyTools

print(MyTools.__name__)

print(__name__)

C:\PythonTest>python MyMain.py

结果:

MyTools

__main__

7.8 包

包是一个分层次的文件目录结构,它定义了一个由模块及子包下的模块的组成结构。众所周知世界分5大洲,其中有亚洲,亚洲里包含中国、印度,它们的首都分别是北京和新德里。我们就通过python代码结合这个层次来演示下包的概念,它们的层次可表示为下图树形结构:

C:\PythonTest>tree /f

Python基础概念_6_模块_python

注:
1这里为了演示方便仅贴出了MyPackage.py和beijing.py的代码因为它们的内容大同小异。
2 这里tree是windows/linux里的命令,可以显示目录的树形结构。通过上面可以看出文件夹china和india是一级的。

MyPackage.py代码:

importworld.asia.china.beijing as beijing
importworld.asia.india.newdelhi as newdelhi
importworld.asia.indiadesc as india
importworld.asia.chinadesc as china
importworld.asiadesc as asia
importworlddesc as world
if__name__ == '__main__':
    print(beijing.getCurrentLevelName())
    print(newdelhi.getCurrentLevelName())
    print(india.getCurrentLevelName())
    print(china.getCurrentLevelName())
    print(asia.getCurrentLevelName())
    print(world.getCurrentLevelName())

beijing.py代码:

defgetCurrentLevelName(LevelName='beijing'):
    return "我在第"+str(4)+"层,我是:"+LevelName+"(北京)"+"。我的上层是china(中国)"
 
执行MyPackage.py
C:\PythonTest>python MyPackage.py

结果:

我在第4层,我是:beijing(北京)。我的上层是china(中国)

我在第4层,我是:newdelhi(新德里)。我的上层是india(印度)

我在第3层,我是:india(印度)我的上层是asia(亚洲)

我在第3层,我是:china(中国)我的上层是asia(亚洲)

我在第2层,我是:asia(亚洲)我的上层是world(世界)

我在第1层,我是:world(世界),我的上层没了

注:

1需要注意个细节,包同一级内的文件夹里不能再存在和包相同的py文件,如果存在了也不能引用里面的模块。

2 部分源代码见下:chinadesc.py及indiadesc.py方法与外围的worlddesc.py方法类似,打印的名字不同而已.以下以MyPackage.py和worlddesc.py为例:

MyPackage.py源码:

import world.asia.china.beijing as beijing
import world.asia.india.newdelhi as newdelhi
import world.asia.indiadesc as india
import world.asia.chinadesc as china
import world.asiadesc as asia
import worlddesc as world
if __name__ == '__main__':
	print(beijing.getCurrentLevelName())
	print(newdelhi.getCurrentLevelName())
	print(india.getCurrentLevelName())
	print(china.getCurrentLevelName())
	print(asia.getCurrentLevelName())
	print(world.getCurrentLevelName())


worlddesc.py源码:


def getCurrentLevelName(LevelName='world'):
	return "我在第"+str(1)+"层,我是:"+LevelName+"(世界)"+",我的上层没了"

完整示例代码详见资源:

7.9 总结

通过本章的学习我们知道了模块可更好将函数封装起来,还知道了如何自己定义一个模块,以及自己通过包的方式管理模块,以及怎么看模块的内置属性。接下来,来了解另外个概念数据结构。