共计 5447 个字符,预计需要花费 14 分钟才能阅读完成。
一、模块概述
-
命名空间
由于在 Python 中一切皆为对象(Object), 想要好好理解 Module 和 Package,一定要先理解 Namespace 的概念。所谓 Namespace,是指标示符的可见范围。对于 Python 而言,常见的 Namespace 主要有以下几种
- Build-in Namespace (内建命名空间)
- Global Namespace (全局命名空间)
- Local Namespace (局部命名空间)
有了命名空间的概念,可以有效的解决函数或者是变量重名的问题。不同的命名空间中允许出现相同的函数名或者 是变量名。它们彼此之间不会相互影响,例如在 Namespace A 和 B 中同时有一个名为 var 的变量,对 A.var 赋值并不 会改变 B.var 的值。
-
为什么使用模块?
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越难以维护
-
模块概述
为了编写可维护性的代码,我们会把很多函数进行分组,分别放到不同的文件里去。这样,每个文件包含的代码就相对较少,大多数编程语言都是采用这种方式来组织代码的,在 python 中,一个.py 文件就称之为一个模块
其中定义的所有函数或者是变量都属于这个 Module。这个 Module 对于所有函数而言就相当于一个全局的命名空间。而每个函数又都有自己局部的命名空间。
-
优点
- 提高了代码的可维护性
- 提高了代码的复用度,编写代码不必从零开始,当一个模块编写完成,就可以在其他地方引用
- 引用其他模块,包含 python 内置模块和第三方模块
- 避免函数名和变量名等命名的冲突
-
模块分类
-
标准库模块
-
第三方模块
-
自定义模块
-
二、使用标准库中的模块
-
time
import time now = time.strftime("%Y-%m-%d %H:%M:%S") # 获取当前时间 print(now)
-
random
import random random_num = random.randrange(3) # 返回 012 的随机数 print(random_num)
三、使用自定义模块
-
新建一个名为 speak.py 文件
# speak.py '''This is only a test module''' name = 'zutuanxue_com' age = 18 def speak(): print("zutuanxue_com is a very good man!")
-
import 语句
-
作用
导入模块 / 包
-
格式
import module1[, module2[, module3[, ……]]]
import module1 as 别名[, module2[, module3[, ……]]] 起别名
-
注意
一个模块只会被导入一次,不管你执行了多少次 import,有效的防止导入模块被一次次的执行
-
使用模块中的内容
module. 方法 / 类 / 变量
不起别名实例
>>> import speak # 导入 speak 模块 >>> speak.name # 获取模块 speak 中 name 的值 zutuanxue_com >>> speak.age # 获取模块 speak 中 age 的值 18 >>> speak.speak() # 调用模块中 speak 方法 zutuanxue_com is a very good man! >>> print speak.__doc__ # 获取模块说明 This is only a test module
起别名实例
>>> import speak as s # 导入 speak 模块 并起别名为 s >>> s.name # 获取模块 speak 中 name 的值 zutuanxue_com >>> s.age # 获取模块 speak 中 age 的值 18 >>> s.speak() # 调用模块中 speak 方法 zutuanxue_com is a very good man! >>> print s.__doc__ # 获取模块说明 This is only a test module
-
-
from … import 语句
-
作用
从模块中导入一些指定的部分
-
格式
from module import name1[, name2[, name3[, ……]]]
实例
>>> from speak import name,age,speak # 从 speak 模块导入 name,age,speak >>> name # 获取模块 speak 中 name 的值 zutuanxue_com >>> age # 获取模块 speak 中 age 的值 18 >>> speak() # 调用模块中 speak 方法 zutuanxue_com is a very good man!
-
-
from … import * 语句
-
概述
将模块中所有非下划线开头的成员都导入
-
作用
把一个模块中所有的内容全部导入当前命名空间
-
格式
from modulename import *
-
注意
不应该过多使用,很可能造成变量名的冲突
实例
>>> from speak import * # 会将 speak 模块中非下划线开头的成员都导入当前命名空间中 >>> name # 获取模块 speak 中 name 的值 zutuanxue_com >>> age # 获取模块 speak 中 age 的值 18 >>> speak() # 调用模块中 speak 方法 zutuanxue_com is a very good man!
-
四、__all__
接口暴露
-
概述
代码中是不提倡用
from xxx import *
的写法的,但是在 console 调试的时候图个方便还是很常见的。如果一个模块spam
没有定义__all__
,执行from spam import *
的时候会将spam
中非下划线开头的成员都导入当前命名空间中,这样当然就有可能弄脏当前命名空间。如果显式声明了__all__
,import *
就只会导入__all__
列出的成员。如果__all__
定义有误,列出的成员不存在,还会明确地抛出异常,而不是默默忽略。 -
格式
__all__ = ["name1", "name2"...]
-
作用
Python 不像 Ruby 或者 Java,Python 没有语言原生的可见性控制,而是靠一套需要大家自觉遵守的”约定“下工作。比如下划线开头的应该对外部不可见。同样,
__all__
也是对于模块公开接口的一种约定,比起下划线,__all__
提供了暴露接口用的”白名单“。一些不以下划线开头的变量(比如从其他地方import
到当前模块的成员)可以同样被排除出去。 -
新建 test_all.py
# test_all.py '''This is only a test __all__ module''' __all__ = ["name", "speak"] # 排除了 age name = 'zutuanxue_com' age = 18 def speak(): print("zutuanxue_com is a very good man!")
五、模块循环引用
-
概述
出现循环引用其实就是模块之间发生了相互依赖,A 依赖 B,B 依赖 A,这样他们直接相互依赖,引用的时候就会出现者循环引用(交叉引用)
-
现象
有两个模块 moduleA 和 moduleB
moduleA.py
from moduleB import b def a(): print('我是 A 模块的 a 方法') moduleB.b() def c(): print('我是 A 模块的 c 方法') if __name__ == '__main__': a()
moduleB.py
from moduleA import c def b(): print('我是 B 模块的 b 方法') c()
-
导入的实质
导入其实是要将 被导入模块所有的顶格代码都执行一遍,遇到函数和类的定义会作申明
如果 b 模块中有这么一句print('我是 B 模块')
你在 a 模块 impot b 时就会 执行 print(‘bbb’)这一句
回到循环引用中,首先导入 B, 进入 B 中,发现 B 中又导入了 A 又回到 A 中,但是 A 又导入 B 这就形成了循环引用
-
解决方式 1(直接导入模块名,通过模块调用其中的函数)
moduleA.py
import moduleB def a(): print('我是 A 模块的 a 方法') moduleB.b() def c(): print('我是 A 模块的 c 方法') if __name__ == '__main__': a()
moduleB.py
import moduleA def b(): print('我是 B 模块的 b 方法') moduleA.c()
-
解决方式 2(使用延迟导入(lazy import))
内部导入
"""moduleB.py""" def b(): from moduleA import c print('我是 B 模块的 b 方法') c()
六、__name__
属性
-
概述
每个模块都有一个__name__属性,当其值为“main”时表明该模块自身在运行,否则是被当做模块导入,此时值为模块的名字
-
实例
# speak.py '''This is only a test module''' name = 'zutuanxue_com' age = 18 def speak(): print("zutuanxue_com is a very good man!") if __name__ == '__main__': speak()
-
__name__
作用模块就是一个可执行的 python 文件,一个模块被另一个模块导入,想让模块中的某一段代码不执行,可以使用
__name__
属性来使程序隐藏该段代码,当自身执行时在执行该块代码。一般作为判断是否是作为主运行文件 -
扩展
以后主要用于程序入口使用(项目启动文件中使用)
"""Main.py"""
def main():
pass
if __name__ == '__main__':
main()
七、包
-
需求
如果不同的人编写的模块名相同怎么办?
-
解决
为了避免模块名的冲突,python 又引入了按目录来组织模块的方法,称为包(package)
-
特点
引入包以后,只要顶层包名不与别人冲突,那么所有的模块都不会与别人冲突
-
注意
每个包目录下都会有一个名为
__init__.py
的文件,说明这个目录是个 python 包,还可以导出包中的内容 -
建包
新建文件夹名称为 lucky_package 文件夹
目录结构
project/ lucky_package/ __init__.py # 声明 lucky_package 为一个包 speak.py # 模块 speak test.py # 用于测试 lucky_package 包的使用
实现
-
方式一 通过 pycharm 直接创建 Python 包
选择模块 -> New -> Python Package
-
输入包名
点击 OK
-
方式二 手动创建
- 模块 -> New -> Directory
- 输入 lucky_package
- 点击 OK
- lucky_package -> New -> Python File
- 输入文件名称为
__init__.py
- 点击 OK
-
包内创建模块
speak.py
# speak.py '''This is only a test module''' name = 'zutuanxue_com' age = 18 def speak(): print("zutuanxue_com is a very good man!") if __name__ == '__main__': speak()
-
使用
test.py
-
第一种导入方式使用
>>> from lucky_package import speak # 从 zutuanxue_com_package 包导入 speak 模块 >>> speak.name # 获取模块 speak 中 name 的值 zutuanxue_com >>> speak.age # 获取模块 speak 中 age 的值 18 >>> speak.speak() # 调用模块中 speak 方法 zutuanxue_com is a very good man!
导包重命名
>>> from lucky_package import speak as s # 从 zutuanxue_com_package 包导入 speak 模块并重命名为 s >>> s.name # 获取模块 speak 中 name 的值 zutuanxue_com
-
第二种导入方式
>>> from lucky_package.speak import name,age,speak # 从 lucky_package 包 speak 模块导入 name,age,speak >>> name # 获取模块 speak 中 name 的值 zutuanxue_com >>> age # 获取模块 speak 中 age 的值 18
-
第三种导入方式
>>> from lucky_package.speak import * # 从 lucky_package 包 speak 模块导入 所有成员 >>> name # 获取模块 speak 中 name 的值 zutuanxue_com >>> age # 获取模块 speak 中 age 的值 18
-
第四种导入方式
>>> import lucky_package.speak # 导入 lucky_package 里 speak 包 >>> lucky_package.speak.name # 获取 name 的值 zutuanxue_com
-
第五种导入方式
import lucky_package.speak as s # 导入 lucky_package 里 speak 包
s.name # 获取 name 的值
zutuanxue_com -
-
填充包
__init__.py
代码-
方式一 在 init.py 中 导入模块
__init__.py
from . import speak
使用
>>> from lucky_package import speak # 导入 lucky_package 里 speak 包 >>> speak.name # 获取 name 的值 zutuanxue_com
-
方式二
在 init.py 中 导入模块所有成员
__init__.py
from .speak import *
使用
>>> from lucky_package import * # 导入 lucky_package 里 speak 包 >>> name # 获取 name 的值 zutuanxue_com
-
注意
不建议这样使用方式
-