这篇文章将会介绍 Python 中模块与包的相关内容


1、模块与包

模块 (module)   这个概念最初是为了代码封装和可重用性而出现的,每个后缀为 .py 的文件都是一个模块

(package) 是为了更好地组织模块而发展出来的概念,在 Python 3.3 后,每个目录都被称为一个包

而在 Python 3.3 之前,只有目录中有 __init__.py 才会被识别为一个包

2、导入模块

我们可以使用 import 语句导入模块,常规的语法是 import module, 在首次导入模块时:

  1. 首先创建一个新的命名空间,并在该命名空间内执行模块 module 中的代码
  2. 然后在当前命名空间用名称  module  引用新的命名空间 

所以我们在当前命名空间内才能通过 module.symbol 访问模块中的变量

>>> import random
>>> random.randint(0, 1)
# 1

我们也能使用 from module import symbolmodule 中导入指定的 symbol 到当前命名空间

这样我们就能在当前命名空间直接访问导入的变量,但是要注意此时不能访问模块中的其他变量

>>> from random import randint
>>> randint(0, 1)
# 1

我们还能通过 as 用指定的名称引用新的命名空间和导入的变量

>>> # 通过 `as` 指定名称引用新的命名空间
>>> import random as rd
>>> rd.randint(0, 1)
# 1
>>> # 通过 `as` 指定名称引用导入的变量
>>> from random import randint as ri
>>> ri(0, 1)
# 1

3、导入包

我们可以用 import 语句导入包,常规的语法是 import package,在执行这条语句时:

  1. 首先创建一个新的命名空间,并在该命名空间内执行包内 __init__.py 中的代码
  2. 然后在当前命名空间用名称 package 引用新的命名空间

__init__.py 一般用于指定导出的内容,若该文件缺失或内容为空,import package 不会有任何效果

import package

print(package.module.symbol)

我们也能用 from package import modulepackage 中导入指定的 module 到当前命名空间

这样我们就能在当前命名空间直接访问导入的模块 module 以及模块中的变量

from package import module

print(module.symbol)

我们还能用 from package.module import symbolpackage 中的 module 导入指定的 symbol

这样我们就能在当前命名空间直接访问导入的变量 symbol

from package.module import symbol

print(symbol)

4、搜索路径

下面让我们思考一个更深入的问题?当我们使用 import 语句导入模块时,解释器在哪里找所需的模块呢?

  1. 缓存路径(可以通过 sys.modules 查看,保存着之前导入的所有模块及其查找路径)
  2. 内置模块(可以通过 sys.builtin_module_names 查看)
  3. 其他位置(可以通过 sys.path 查看,包括入口文件所在目录、PYTHONPATH 环境变量指定目录)

如果现在我们需要让程序引用一个不在上述路径所指定的目录中的模块,可以怎么处理呢?

一个简单而有效的办法就是在程序中修改 sys.path 的值,添加上述模块所在路径即可

5、隐藏测试代码

在编写模块时,我们常常需要对模块进行单元测试,等待测试成功后才会将其应用到其它程序上

由于测试所需,在模块中可能会留下大量测试代码,这些测试代码在模块被引用时可能会影响到正常运行

所以,我们有必要在模块中隐藏测试代码,具体的方法如下:

在 Python 中有一个内置变量 __name__,只有当一个文件作为入口文件时,它的值才为 __main__

所以我们可以将测试代码写在以下条件语句块内,这样的话只有在直接运行模块时才会执行这些代码

if __name__ == '__main__':
    # 测试代码

6、模块查询

最后一个问题,当我们看到一个从未接触过的模块时,可以在哪里进行学习呢?通常有以下几种途径:

  • mudule.__doc__:列出模块的简短说明
>>> import random
>>> print(random.__doc__)
# Random variable generators.
# 
#     integers
#     --------
#            uniform within range
# 
#     sequences
#     ---------
#            pick random element
#            pick random sample
#            pick weighted random sample
#            generate random permutation
# 
#     distributions on the real line:
#     ------------------------------
#            uniform
#            triangular
#            normal (Gaussian)
#            lognormal
#            negative exponential
#            gamma
#            beta
#            pareto
#            Weibull
# 
#     distributions on the circle (angles 0 to 2pi)
#     ---------------------------------------------
#            circular uniform
#            von Mises
# 
# General notes on the underlying Mersenne Twister core generator:
# 
# * The period is 2**19937-1.
# * It is one of the most extensively tested generators in existence.
# * The random() method is implemented in C, executes in a single Python step,
#   and is, therefore, threadsafe.
  • module.__all__:列出模块的可用接口
>>> import random
>>> print(random.__all__)
# ['Random', 'seed', 'random', 'uniform', 'randint', 'choice', 'sample', 'randrange', 'shuffle', 'normalvariate', 'lognormvariate', 'expovariate', 'vonmisesvariate', 'gammavariate', 'triangular', 'gauss', 'betavariate', 'paretovariate', 'weibullvariate', 'getstate', 'setstate', 'getrandbits', 'choices', 'SystemRandom']
  • module.__file__:打印模块源代码的所在路径
>>> import random
>>> print(random.__file__)
# C:\Python\Python37-32\lib\random.py
  • help(module):查看帮助手册,获取更多信息
  • 最后一个方法当然是直接看官方文档的说明啦:https://docs.python.org