之前我们在学习中,我们写的python都是只需要放在一个文件,内容较少

但是在实际的项目中,代码量可能非常大,可能几十万行代码都有可能,这样放在一个文件中显然不合适

为了编写可维护的代码,我们把代码安装功能点分割出来,分别放到不同的文件里,这样,每个文件包含的代码相对较少

基本上大部分编程语言都编程语言都采用这种组织代码方式

在python中,代码是放在py为扩展名的文件中,一个.py文件就称之为一个模块(Module)

我们又可以把许多模块按照功能放大不同的目录中来组织。这些组织存放模块文件的目录,我们称之为包(Package)

6.1模块和包的作用

为什么要使用模块和包呢?

首先,它大大提高了代码的可维护性。一个模块可以引用另一个模块里面的对象(包括数据和函数)。我们在编写程序的时候,

经常引用其他模块,包括我们自己写的模块,python内置的模块,还有后来安装的第三方模块。

其次,使用模块还可以避免函数名和变量名冲突,可以想象,如果一个代码文件特别的大,实现很多功能,难免其中有些变量的名字会发生重复。这时候我们要绞尽脑汁想出不同的变量名或者函数名。如果采用模块分割代码,每个模块文件代码都不是很多,就可以大大的缓解这个问题

6.2.自定义模块

假设我们需要将一个计算数字平方和立方的函数,放到一个模块calc.py里面,其内容如下:

var1 = 20

def calc_s(num):
    print('square of num is %s' % num**2)

def calc_s(num):
    print('cube of num is %s' % num**3)

def calc_s_c(num):
    print('square of num is %s' % num**2)
    print('cube of num is %s' % num**2)

现在我们要在别的模块里面使用该模块里面的calc_s_c函数,该怎么做呢?

在使用别的模块里面的变量和函数时,首先需要把它们“弄”到当前模块来,需要用到import这个关键字

import calc
cal.calc_s_c(10)

上面这种方法就是把calc模块对象(注意 模块在python中也是对象)导入到当前模块中了,并且当前模块中还是用calc这个变量

指向该模块。这里模块名就是文件名(不需要扩展名.py)

 

当然,我们也可以用另一种方式

from calc import calc_s_c

calc_s_c(10)

这样就把calc模块里面的calc_s_c函数对象(注意:python中,函数也是对象)导入到当前模块中,并且当前模块中还是要用calc_s_c这个变量指向该函数对象

那如果我们除了要使用calc_s_c,还要使用calc_s,可以这样

from calc import calc_s_c,calc_s

cals_s_c(10)
cals_s(10)

 

同样的,我们导入模块的时候,可以多个模块一起导入,例如:

import modeule1,modue2,modul3

 

上面的例子还要个偷懒的方法

from calc import *
calc_s_c(10)
calc_s(10)

这里import * 把calc模块所有可以导入的对象全部都导入了。包括calc_s_c,calc_s,calc_c函数,还要那个变量var1

 

我们在导入对象的时候,还可以把导入对象原来的变量名字改掉

import calc as c
c.calc_s_c(10)
from calc import calc_s_c as sc
    sc(10)

6.3.自定义包

当项目比较大的时候,往往光有自定义模块还是不够的,想象一下,在一个目录下放置几十上百的模块文件是多么乱

所以,python允许我们将功能相关的模块放到相应的目录结构中来组织模块。这些组织存放模块文件的目录,我们称之为包(Package)

但是python要求这些包目录一定要有一个特别的文件__init__.py,在里面

下面是一个Package目录结构的例子

Phone/
    __init__.py
   common_util.py
   voicedta/
         __init__.py
        post.py
        isdn.py
    Fax/
         __init__.py
         G3.py
Mobile/
    __init__.py
    Analog.py
    Digital.py
  Pager/
    __init__.py
    Numeric.py

Phone是最顶层的package而Voicedta,Fax,Mobile,Pager都是子package。导入子packages,导入子packages,可以这样写

import Phone.Mobile.Analog
Phone.Mobile.Analog.dial()

当然也可以使用from...import...的方式,下面这几种方式的使用都可以

from Phone.Mobile import Analog
Analog.dial('30')
from Phone.Mobile.Analog import dial
dial(323)

在范例的目录结构里面。__init__.py文件是初始化文件。在我们使用from-import语句的时候,会执行里面的代码。它是必须要存在的

,即使没有初始化工作要做,也必须有这个空文件

6.4.使用内置模块

之所以用python可以比其他语言写出更加简洁的代码,一个原因是python高层抽象的简洁的语法,另一个重要原因就是其丰富

的内置库和海量优秀的第三方库。

内置模块就是python安装的时候就提供的功能模块和包,python以及贴心的帮我妈把程序设计中常用的功能都做好了,放在内置库

我们只需要导入就可以使用。

例如:我们需要获取系统当前时间,只需要导入时间库time.

import time
getTime = time.strftime('%Y-%m-%d %H:%M:%S')
print(getTime)

结果如下

D:\tools\Python37-32\python.exe E:/samples/modules/m0.py
2019-07-29 14:59:49

 

如果我们要调用外部的计算机程序,只需要导入os操作库os

#调用外部的计算机程序,以QQ为例子
import os
os.system(r'D:\Tencent\QQ\Bin\QQScLauncher.exe')

就可以打开计算机程序了。

内置库非常丰富,大家可以在需要的时候,用搜索引擎搜索一下就可以找到范例代码了

10.5.模块搜索路径

上面学习中,你可能会有个疑问。我们用import或者from ... import来导入模块的时候python解释器是怎么找到模块文件

并且加载出来的

python是根据sys模块的一个变量内容sys.path的列表值来决定的,我们看一个例子:

第六章、模块(Moudule)与包(package)和库_算法

 

那么sys.path的值又是怎么来的呢?

python解释器启动过程中一般会将下面的路径加到sys.path里面去

  ** 启动脚本所在的目录

  ** PYTHPATH环境变量里包含的目录,如果没有设置则忽略。该环境变量设置和PATH环境变量的设置方法类似

  ** 标准库目录,已经随着python的安装进入到计算机的那个,就是那个 lib/site-pacjages目录

  ** lib/site-packages下面.pth文件里指定的路径

上面列出的路径是python解释器启动过程自动得到的搜索路径,当然我们也可以自行修改那个sys.path里面的内容

,动态的改变模块搜索路径。课堂上我们会给出一个实际的例子