Python - 模块
概述
- python 模块
- 写完回头一看, 感觉是不是有点长
- 明明可以拆分得更细的
- 写完回头一看, 感觉是不是有点长
- python 模块
背景
- 复习 python
- 也说不上复习, 因为之前就没学进去
- 单个脚本的内容, 我暂时还没有 复习到
- 囧...
- 模块对我来说, 一直是一个 比较模糊的概念
- 特别是 学过Java 的同学
- 模块有点像 类, 有点像 包
- 但又不能完全对上
- 反正对我来说, 确实有点困扰
- 特别是 学过Java 的同学
- 复习 python
准备
os
- win10
python
- 3.7.0
shell
- mintty 2.9.4
1. 模块的引入
概述
- 模块的引入
场景
场景1: 使用 math 库
场景
- 刚开始学习 python 的时候, 我们总会沉迷于 加减乘除 等数学运算, 无法自拔
- 但是当我们需要复杂计算的时候, 我们会使用 简单运算 来做组合
- 比如 复数 的计算
- 但是还有一些 复杂运算, 我们好像无法实现
- 比如 sqrt
- 所以, 如果我们要使用的话, 怎么办嗯?
结果
使用 math 库
import math math.sqrt(<arg>)
这个 不知道怎么来 的 math, 就这样帮助我们完成了任务
场景2: 代码复用
场景
- 我在一个脚本里写了个函数, 感觉挺不错的样子
- 并且在很多别的场景下, 这个函数也可以复用
- 如果不能复用, 我需要每个脚本都实现一遍
- 麻烦不说, 还容易出错
所以
- 我能不能像 math 库那样, 复用自己的代码
- 当然可以啦
- 我能不能像 math 库那样, 复用自己的代码
模块的好处
书上也没有明确写
- 起码可以解决之前提到的问题
我的看法
分解工程
- 并行开发
- 灵活替换
- 便于维护
方便复用
写模块
- 模块的好处这么多, 学会了也不会有什么坏处
- 既然已经学会了基本的 python 代码, 再做一些简单准备, 就可以写模块了
- 模块的好处这么多, 学会了也不会有什么坏处
2. 模块
概述
- 模块是什么
模块
模块 是 写有 python 代码的文件
- 怎么觉得, 和 脚本 也没什么区别
和 脚本 的区别
脚本
- 直接执行的 python 文件
模块
- 通常不会直接执行
- 但是会被别的 脚本/模块 导入, 帮助程序运行
其实本质上, 并没有什么区别
模块里有什么
- 变量
- 函数
- 类型
3. 模块的命名规范
概述
- 模块的 命名规范
命名规范
字符集
- 小写字母
- 下划线
书写方式
- 小写字母开头
- 如果有 多个单词, 那么使用 _ 来分割
拓展名
- .py
例子
module.py my_module.py
其他
python 工程里的文件名
- 文件名也遵守和 模块 相同的规范
- 为什么要 讲这个
- 后面会提到的, 别着急
模块名里能否出现数字
能
- 但是不建议以 数字 开头
脚本
- 脚本名中, 可以以 数字开头
- 但是这样的 脚本 作为 模块 导入时, 会出现问题
结论: 能用, 但是不建议
- 有时候, 你可能也不清楚你写的到底是 模块 还是 脚本
4. 路径 与 模块的位置
- 概述
- 路径
1. 疑问1: 模块的导入
问题: 我随便写个模块, 如何才能导入
- 放在哪里
- 用什么命令
解答
- 放在哪里
- python 解释器有自己的 搜索路径
- 用什么命令
- 这个先用 简单的 import
- 放在哪里
2. 路径
路径
- python 解释器会在这些目录下, 搜索模块
查看当前路径
# 进入 python 命令行 # git-bash 下进入交互式命令行的方式 > winpty python # 查看当前路径 ## 1. 导入 sys import sys ## 2. 导入 pprint, 打印的相对友好些, 直接 print 也可以 import pprint ## 3. 查看路径 pprint.pprint(sys.path)
结果
[‘‘, ‘C:\\Programs\\Python\\Python37\\python37.zip‘, ‘C:\\Programs\\Python\\Python37\\DLLs‘, ‘C:\\Programs\\Python\\Python37\\lib‘, ‘C:\\Programs\\Python\\Python37‘, ‘C:\\Programs\\Python\\Python37\\lib\\site-packages‘]
解释
路径们
- ‘‘
- 你没看错, 确实有这个东西
- 代指 当前路径, 即 执行这个 python 脚本的路径
- 其他
- 本地的 python 路径
- ‘‘
也就是说
- 执行脚本的时候, python 解释器会在这些地方, 寻找你的 模块
3. 疑问2: 如何让你的模块, 能被系统找到
问题
- 如何让系统能找到我写的模块
解决
- 思路1: 把模块放到 列出的路径 里
- 最简单的思路
- 思路2: 把 模块所在的路径, 加入这个列表里
- 这个方法好像有点多, 需要说一下
- 思路1: 把模块放到 列出的路径 里
4. 添加路径
方式1: 运行时添加
代码
# 1. 添加到 path 数组最前 sys.path.insert(<path>) # 2. 添加到 path 数组最后 sys.path.append(<path>)
特性
- 运行时添加
- 方便灵活
- 不会影响其他脚本
- 下次运行, 需要重新添加
- 运行时添加
疑问: 添加到 最前 和 最后 有什么区别
- 这个后面说
方式2: 环境变量
变量名
PYTHONPATH
- linux 和 windows 下都可以
PATH
- 这个我没试过
- python 的安装目录, 是在里面的
- 但是 PATH 里的其他目录, 并不在 python 的 path 里
- 所以我不确定
结果
- 添加的变量, 在 当前目录 的后面
- 生效之后, 会影响环境下的 所有python 脚本
5. 疑问2: 重名脚本
问题
- 如果两个脚本重名了, 会导入哪个
解答
- 关于重名
- 首先重名的脚本, 肯定不可能在一个目录下
- 所以, 重名的问题, 变成了一个 优先级 的问题
- 不同路径下的同名脚本, python 解释器会使用哪个
- 思路
- 思路1: 改名
- 这样可以避免冲突, 并且可以同时使用不同模块
- 思路2: 借助优先级, 完成覆盖
- path 其实是有优先级的
- 脚本的导入, 以 优先级 高的路径为准
- 思路1: 改名
- 关于重名
优先级
- 高低
- 不同目录的同名脚本, 只载入 优先级最高 目录下的那个
- 由 path 数组里的顺序决定
- 越靠前 越高
- 所以之前 insert 和 append 的区别, 就在这里
- 高低
5. 模块的导入
- 概述
- 模块的导入与使用
1. 模块的内容
概述
- 模块里有 那些内容
内容
- 属性
- 函数
- 类
2. 模块的导入
概述
- 模块的导入方法
方法1: import 基础
代码
# 1. 导入 单个模块 import sys # 2. 导入 多个模块 import sys, pprint # 3. 导入模块, 并起一个别名 import sys as system # 4. 导入多个模块, 并起别名 import sys as system, pprint as prettyprint
使用
# 1. 使用属性时, 需要添加 模块名 作为 前缀 sys.path # 2. 有别名时, 也是如此 system.path
疑问: 有没有办法, 可以不加前缀呢
- 当然有啦
方法2: from import
代码
# 1. 从 sys 模块, 导入 path from sys import path # 2. 导入多个 from sys import path, argv # 3. 起别名 from sys import path as p # 4. 多个别名 from sys import path as p, argv as v
使用
# 直接使用即可 print(path)
注意
同样的模块, 只会 import 一次
就算你运行多次 import 语句, 也只会 import 一次
这样可以避免 出现循环依赖 时的 无限死循环
如果你需要重新 import, 需要使用下列语句
import importlib import.reload(<module>)
模糊导入: from import *
代码
# 可以一次导入 模块愿意暴露 的所有内容 # 对应的, 其他单词导入 确定内容的导入, 被称为 精确导入 from sys import *
不建议使用
- 可能会和 本模块变量/方法 冲突
- 可能会和 其他模块变量/方法 冲突
不会导入导入
_
开头的 变量 和 方法- import 里可以导入
all
作用
- 定义 python 模块在 模糊导入 下, 可以被导入的内容
查看
# 并不是 所有的模块 都有 # sys 是没有的 import copy copy.__all__
定义
# 这些都是 属性, 函数, 类 的名字 __all__ = ["Error", "copy", "deppcopy"]
如果不定义
- 没有 all 属性
- 暴露所有不以
_
开头的内容
6. main
概述
- 简述 main
场景: 想做要给测试
场景
- 定义好了模块里的函数, 想在模块里运行来做测试
- 在 模块里 直接执行 函数
- 模块被导入, 函数又执行了一遍
- 不太想这样
解决
- 在别的模块里, 来对这个模块进行测试
- 这个是比较科学的方法
- 将测试内容, 移动到 main 方法下
- 在别的模块里, 来对这个模块进行测试
代码
# 将 测试代码, 放到 这个块里, 即可 if __name__ == ‘__main__‘:
name
作用域名称
- 作用
- 标识 代码执行 作用域
- 作用
作用域
- main
- 顶层作用域
- 模块作为 脚本 执行的时候, 会是这个结果
- 表示模块是 直接被执行
- 顶层作用域
- moduleName
- 模块本身名称
- 模块作为 模块 被引入, 会是这个结果
- 模块本身名称
- main
作用
- 判断当前模块的状态
- 判断之后, 可以根据状态来 区分行为
- 执行入口
- 模块
- 判断之后, 可以根据状态来 区分行为
- 判断当前模块的状态
7. 包
概述
- python 的包
包
划分层次结构的目录
- 其实包就是 另一种 模块
内容
- 模块
- 其他的 包
- init
一段往事
找不到模块
- 刚开始学 python
- 创建了一个 文件夹, 在里面写了个 python 脚本
- 文件夹外的脚本, 想引用 文件夹 里的 python 脚本
- 结果 死活 import 不到东西
解决
- 在文件里创建了一个 init.py
- 我奇怪的是, 里面啥也没有, 为啥就把问题解决了
- 在文件里创建了一个 init.py
1. init.py
概述
- init.py 文件
作用
python 文件
语句
- 会被执行
- 甚至能在 init.py 文件下, import 别的模块...
- import 当前模块子模块的话, 必须带上当前模块的名字...
- 有点不理解
- import 当前模块子模块的话, 必须带上当前模块的名字...
定义 变量, 方法
- 也可以
- 使用 ./ 使用
- 但是不建议
包的 标识
- 没有这个文件, 目录不会被 python 识别成包
限定 模糊导入 的范围 - from import *
限定范围
# 模糊导入时, 只导入 以下模块 # 可以递归 # 精确导入时, 可以指定不在 __all__ 里的模块 # 如果不定义 __all__, 则暴露所有 非`_`开头的内容, 思路 和 模块一致 __all__ = ["<moduleName01>", "<moduleName02>", "<moduleName03>"]
ps
ref
- python 基础教程(3rd)
- chpt10
- python命名规范
- 命名规范
- Python 中模块与包的概念
- 讲得挺不错
- Can a Python package name start with a number?
- 从 实现的角度, 讲了模块名为什么不能用 数字 开头
- Python Packaging User Guide
- python 打包指南
- python导入模块路径优先级问题
- 模块优先级, 讲得还可以
- Python导入模块,Python import用法
- import 的讲解
- 还不错
- 这个网站有很多其他的讲解, 也挺好
- 不过现在好些内容需要 付费解锁 了, 囧
- import 的讲解
- main --- 顶层脚本环境
- 包的引用
- Python init.py 文件使用
- python 基础教程(3rd)
后续
- 类
- 方法