“Life is short, You need Python” – Bruce Eckel
Environment
- OS: macOS Mojave
- Python version: 3.7
- IDE: Jupyter Notebook
文章目录
- 0. 写在前面
- 1. 概念
- 2. 导入
- 3. 创建
- 3.1 创建模块
- 3.1.1 name
- 3.1.2 doc
- 3.1.3 all
- 3.2 创建包
- 3.2.1 init 文件
- 4. 搜索路径
0. 写在前面
“Python 自带电池”,指的就是 Python 标准库,它随着 Python 的安装被安装到了本地,其中包含了许多好用高效的内置模块们,如 os、pickle 等。
“You don’t have to reinvent the wheel.” Python 有大量的第三方库,如进行数据分析,常会用到 numpy、scipy、pandas 等包,有称呼 numpy 和 scipy 作科学计算库。此外,还有爬虫框架(scrapy等),深度学习框架(tensorflow、pytorch等),web应用框架(flask、django等)。
1. 概念
在日常使用中,不管是 模块 还是 包 还是 库或是框架,import
就完事了。但搞搞清楚区别还是要的。
- 一个以 .py 结尾的 Python 代码文件就是一个 模块(module),实质上是变量、函数和类的集合。这些模块的路径为
/anaconda3/envs/环境名/lib/python3.7/
- 包(package) 就是包含一些模块文件和一个 __init__.py 文件的目录,实质上是模块的集合。为了在实际开发中方便地管理许多不同的模块,将模块们放进不同的目录。包的路径为
/anaconda3/envs/环境名/lib/python3.7/site-packages/
- 库(library) 强调的是功能性,表示完成一定功能的代码的集合,可以是一些模块的集合,如内置模块们来自 Python 标准库;可以是一个包,如numpy 和 scipy 又被称为科学计算库。区别于 Python 库,其他来源的库都可以称为为“第三方库”。
- 框架(framework) 是库的集合,提供解决问题的一整套方案。与 库 的不同之处在于,框架 存在较强的约束性,需要按照其中的规则办事,像是一门独立的语言。
2. 导入
-
import 模块名 [as 别名]
导入整个模块,可以在一行导入多个模块。通过模块名或别名.函数名或变量名或类名
调用
import random, math
random.seed(0)
print(random.randint(1, 3)) # 2
print(math.e) # 2.718281828459045
-
from 模块名 import 函数名或变量名或类名 [as 别名]
导入模块中特定的函数或变量或类,调用时可以省略模块名;拒绝使用from 模块名 import *
导入模块中所有的方式。
from random import randint
# 随机从 1 到 3 的整数中返回一个
res = randint(1, 3)
若导入的函数名(或变量名或类名)与已有的同名,将发生覆盖。可见,from 模块名 import *
更容易带来麻烦,因此别这么干。
e = 666
from math import e
print(e) # 2.718281828459045
3. 创建
3.1 创建模块
关注两个属性,__name__、__doc__ 和 __all__
3.1.1 name
在 Python 执行文件中运行 __name__
print(__name__) # 输出 __main__
在编写模块时,其中有一些代码,如测试代码,只希望在模块单独作为程序运行时被执行,可以放在 if __name__ == '__main__:'
中,建议格式如下
def main_or_test():
# 模块单独作为程序运行时,要执行的代码
pass
if __name__ == '__main__':
main_or_test()
例 如下编写一个模块 bar,放在当前 Python 执行文件同目录下
# bar.py
def baz():
print('baz is being called.')
baz()
使用 import 导入这个模块时,baz 函数被调用了
import bar
# baz is being called.
This is not exactly what we want. 得使用 if __name__ == '__main__:'
,就称心如意了
import bar
bar.baz()
# baz is being called.
进一步,使用 main
函数符合编程的传统
3.1.2 doc
与函数文档类似,在开头使用成堆的三个连续双引号写一些内容,作为模块的文档,在调用时可以以 模块名.__doc__
查看内容
如上 profile 库
import profile
print(profile.__doc__)
# Class for profiling Python code.
3.1.3 all
- 若未在模块中编写
__all__
列表,那么from 模块名 import *
(但也别这么导入)将导入所有 不以下划线开头的 变量、函数、类; - 若在模块中编写了
__all__
列表,那么在 from 模块名 import * 时,会导入名字属于__all__
列表元素的变量、函数、类。
导入模块后可以使用 模块名.__all__
查看该属性
import profile
print(profile.__all__)
# ['run', 'runctx', 'Profile']
3.2 创建包
将相关的模块放进一个目录,并在目录下创建一个 __init__.py 的文件。
例 在执行文件的同目录下创建名为 foo 的包,包含 bar 模块
就可以导入使用了
import foo
foo.bar.baz()
# baz is being called.
3.2.1 init 文件
文件夹中的 __init__.py 是 Python 包 的标识,应尽量保持简单。通常,除了必要的信息和 __all__ 放在 __init__.py,其他内容都放到模块文件中编写。
4. 搜索路径
当使用 import
导入模块或包时,Python 将按以下优先级查找
- 内存(在执行文件中已导入过的)
import foo
foo.bar.baz()
# baz is being called.
# 接着,将 foo 包删除
import foo
foo.bar.baz()
# baz is being called.
可见,若程序未终止,那么在本次运行中 import foo
仍然可行,因为 foo 包已加载入内存中。
- sys.path 包含的路径
在 anaconda 默认环境(base)下,模块的搜索路径可由 sys.path
查看,按照其中的路径由前向后依此查找。
import sys
sys.path
# ['',
# '/Users/xxx/data',
# '/anaconda3/lib/python37.zip',
# '/anaconda3/lib/python3.7',
# '/anaconda3/lib/python3.7/lib-dynload',
# '/anaconda3/lib/python3.7/site-packages',
# '/anaconda3/lib/python3.7/site-packages/aeosa',
# '/anaconda3/lib/python3.7/site-packages/IPython/extensions',
# '/Users/xxx/.ipython']
- 第一个路径
''
表示 .py 执行文件所在的目录; - 内置模块在
'/anaconda3/lib/python3.7'
; - 下载的包在
'/anaconda3/lib/python3.7/site-packages'
; - 若需要将不在该文件夹内的模块导入,则需要将模块的路径添加到
sys.path
之中sys.path.append(new_path)
。