文章目录
- 一、模块就是程序
- 二、模块的搜索路径(sys 模块的使用)
- 三、包
- 四、模块导入时与运行时
- 五、pip 包管理器的使用及其下载源的更改
- 1、pip 包管理器的使用
- 2、pip 下载源的更改
- 六、默认 py2 和 py3 的切换
- [七、Python 常用标准库](https://docs.python.org/2/library/)
- [八、Python 常用第三方库(博客总结)](https://awesome-python.com/)
- 九、参考资料
一、模块就是程序
- 封装性
- 容器:例如
list tuple string set dict
等,这些是对数据的封装。 - 函数:对语句的封装,是可以实现一项或多项功能的一段程序。
- 类:对方法和属性的封装,也就是对函数和数据的封装。
- 模块:是可以实现一项或多项功能的程序块。我们保存的每一个
.py
结尾的文件,都是一个独立的模块,其中,文件名 = 模块名
。
- 导入模块的方法
- import 模块名
- import 模块名 as 新名字
- from 模块名 import 函数名/类名:大型项目中应尽量避免使用此方法,除非你非常确定不会造成命名冲突;它有一个好处就是可直接使用
function()
而不用加module.function()
了
- 模块中变量、函数以及类的属性和方法的调用
module.variable
module.function()
module.class.variable
module.class.method()
# TypeError: unbound method hi_somebody() must be called with hi instance as first argument (got str instance instead)
# 不能直接使用模块中类中的方法,要先将类进行实例化
ins = module.class()
ins.variable
ins.method()
- 模块的
__name__
属性
- 所有程序模块都有一个
__name__
属性,__name__
的值取决于如何应用模块 - 作为独立程序运行的时候,
__name__
属性的值是'__main__'
(将顺序执行if __name__ == '__main__'
: 后面的代码,这样我们就可以做单元测试来检验模块中内容的正确性) - 作为模块导入的时候,
__name__
属性的值就是该模块的名字了(if __name__ == '__main__'
: 后面的代码将不执行)
- 使用模块有什么好处
- 大大提高了代码的可维护性
- 编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用 (代码重用)
- 可以避免函数名和变量名冲突,相同名字的函数和变量完全可以分别存在不同的模块中
- Python2 使用 Python3 的特性
- Python 提供了
__future__
模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性 - eg:
from __future__ import division
二、模块的搜索路径(sys 模块的使用)
- 模块默认搜索路径:
- 程序当前目录
- 标准库的安装路径(eg:
/home/manzp/anaconda2/lib
各种 py 模块文件) - 操作系统环境变量
PYTHONPATH
指向的路径
- 获取及添加模块搜索路径的方法:
import sys
# 一、获取模块搜索路径
sys.path
['', # 当前路径
'/home/manzp/anaconda2/bin', # 可执行文件
'/home/manzp/caffe_ssd/caffe/python', # PYTHONPATH
'/home/manzp/anaconda2/lib/python27.zip',
'/home/manzp/anaconda2/lib/python2.7',
'/home/manzp/anaconda2/lib/python2.7/plat-linux2',
'/home/manzp/anaconda2/lib/python2.7/lib-tk',
'/home/manzp/anaconda2/lib/python2.7/lib-old',
'/home/manzp/anaconda2/lib/python2.7/lib-dynload',
'/home/manzp/anaconda2/lib/python2.7/site-packages', # 第三方库,lib 下为系统库
'/home/manzp/anaconda2/lib/python2.7/site-packages/smop-0.41-py2.7.egg',
'/home/manzp/anaconda2/lib/python2.7/site-packages',
'/home/manzp/anaconda2/lib/python2.7/site-packages/IPython/extensions',
'/home/manzp/.ipython']
# 二、添加模块搜索路径
# 1、加入的是临时搜索路径,程序退出后失效(主程序代码中加入即可,其它代码就能找到,直接使用即可)
sys.path.append('module_path')
sys.path.insert(0, 'module_path') # 定义搜索路径的优先顺序,序号从 0 开始,表示最大优先级
export PYTHONPATH=/home/manzp/caffe_ssd/caffe/python # bash 中执行
# 2、在系统的环境变量里进行配置,使其永久生效
sudo vim ~/.bashrc # 或者 sudo vim /etc/profile
export PYTHONPATH=/home/manzp/caffe_ssd/caffe/python:$PYTHONPATH
source ~/.bashrc # 或者 source /etc/profile
- sys 模块的 argv 变量的用法
- sys 模块有一个
argv
(argument values) 变量,用 list 存储了命令行的所有参数。 -
argv
至少有一个元素,因为第一个元素永远都是.py
文件的名称。
$ python solve.py 0 # 命令行语句
# 获得argv变量的值
sys.argv = ['solve.py', '0']
sys.argv[0] = 'solve.py'
sys.argv[1] = '0'
- 使用 sys.stdout.write() 和 \r 实现进度条
-
sys.stdout
的形式就是 print 的一种默认输出格式,只不过输出不会自动换行 -
\r
回车到本行首,可刷新输出
for i, image_example in enumerate(dataset):
if (i + 1) % 100 == 0:
sys.stdout.write('\r>> %d/%d images has been converted' % (i + 1, len(dataset)))
sys.stdout.flush() # 强制刷新缓冲区,立刻进行打印
三、包
- 包的定义及优点
- Python 把同类的模块放在一个文件夹中统一管理,这个文件夹称之为一个包。
- 如果把所有模块都放在一起显然不好管理,并且有命名冲突的可能。
- 包其实就是把模块分门别类地存放在不同的文件夹,然后把各个文件夹的位置告诉Python。
- Python 的包是按目录来组织模块的,也可以有多级目录,组成多级层次的包结构。
- 包的创建
- 创建一个文件夹,用于存放相关的模块,文件夹的名字即为包的名字。
- 在文件夹中创建一个
__init__.py
的模块文件,内容可以为空(普通文件夹和包的区别)或自定义一些内容;导入一个包的时候,会首先执行这个包中__init__.py
中的代码 - 将相关模块放入文件夹中
__init__.py
实现 包级别模块的预加载:
- 当
__init__
保持为空文件,他就只是标记目录为 python 中的包,导入包中模块的函数时需要使用包.模块
具体指定那个包中的那个模块。因为需要的函数在包中看不到,只在具体模块中可见 - 而
__init__
文件中导入以后,他将成为包级别的内容
,也就是在包中可见,简化了在其它地方的导入
__init__.py
实现包变量的预定义:在__init__
中使用__all__
可以定义from pkg import *
中“*”
包含的内容,不在其中的函数或类在包级别
对外不可见,在模块级别
还是可见的__init__.py
实现 多级包级别别模块的预加载:如下图所示,__all__
里面的函数和类在models 包级别
可见
- 在一级包的初始化中:导入二级包名下的所有模块,这样在一级包就能看到二级包下面的所有模块
- 在二级包的初始化中:导入模块中的所有类和函数,这样在一级包就能看到二级包下面的所有模块中的函数和类
- 在具体模块中:使用
__all__
定义包级别
可见的类、函数 - 使用示例:
from models import resnet18
- 包的管理
- 详见博客: 使用 Anaconda 进行包和环境的管理
- 包的存放路径及包中模块的导入与调用
- 包的存放
- 如果不想把相关的模块文件放在所创建的文件夹中,那么最好的选择就是:放在
site-packages # 默认模块文件存放路径
文件夹里,因为它就是用来存放你的模块文件的。 -
sys.path.append('package_path')
:只是在本程序运行时生效,运行结束后失效。 - 将包的存放路径加入
用户系统环境变量中的PYTHONPYTH
中去,这样在任何位置都可以调用包了,极力推荐!
vim .bashrc
export PYTHONPATH=~/caffe/examples(/package_name) # 只需把包的上一级目录加入PYTHONPATH即可,括号中的内容要去掉,这里写上只为了让大家知道包`package_name`在`~/caffe/examples`目录下。
source .bashrc # 保存后使其立即生效
- 包中模块的导入
- import 包名.模块名
- import 包名.模块名 as 新名字
- from 包名 import 模块名
- from 包名.模块名 import 函数名:
模块级别可见
- from 包名 import 函数名:
包级别可见
- importlib 用法
import importlib
# 一、importlib.import_module(name, package=None),函数有如下两种调用方式:
# - 绝对导入,name为完整路径str,package为None。
# - 相对导入,package需指定对应包位置。
# 与 import time 效果一样
time = importlib.import_module('time')
print(time.time())
# 与 import os.path as path 效果一样
path = importlib.import_module('os.path')
path.join('a', 'b') # results: 'a/b'
# 相对引入, 一级目录,与 import os.path as path 效果一样
path = importlib.import_module('.path', package='os')
path.join('a', 'b') # results: 'a/b'
# 二、importlib 的强大之处是将 import 语句中写死的字面值改成了 import_module 函数中的参数
# 因此可以通过修改参数在外部用变量来控制实际 import 的包或者模块,大大地增加了灵活性
# 设计一个深度学习工具库,里面包含了N个网络模型(ResNet50, HRNet, MobileNet等等),每个模型的实现都有一个
# load_model 的函数。由于计算设备的性能不同,需要调用的网络结构也会变化,我们需要根据外部传入的参数来判断实际 load 哪一个模型
# 采用 import语句 + if-else 判断也能完成这个需求,但此写法冗余,且新增模型时需要修改调用处的代码,添加对应的import语句
def run(model_name, input):
if model_name == 'resnet_50':
from resnet_50.model import load_model
elif model_name == 'hrnet':
from hrnet.model import load_model
elif model_name == 'moblienet':
from mobilenet.model import load_model
model = load_model()
output = model(input)
return output
# 采用 importlib 大大简化代码
def run(model_name, input):
load_model = importlib.import_module('load_model', package='{}.model'.format(model_name))
model = load_model()
output = model(input)
return output
# 从包级别动态的导入配置文件中的类和函数(!!!)
package = importlib.import_module(cfg.package_name) # 动态导入指定名称的包
function = getattr(package, cfg.function_name) # 动态获取包中指定名称的函数对象
result = function() # 调用被导入的函数
# 直接从顶层包级别动态的使用模块中的类或函数:需要在各级包中提前导入
import models
self.model = eval('models.' + self.cfg.MODEL.NAME +'(self.cfg.MODEL.NUM_CLASSES, self.cfg.MODEL.PATH)')
- 包中模块的变量、函数以及类的属性和方法的调用
package.module.variable
package.module.function()
package.module.class.variable
package.module.class.method()
# TypeError: unbound method hi_somebody() must be called with hi instance as first argument (got str instance instead)
# 不能直接使用包中模块的类的方法,要先将类进行实例化
ins = package.module.class()
ins.variable
ins.method()
四、模块导入时与运行时
- 导入时或运行时
模块中的顶级代码
(打印、变量赋值、类的定义等)及类中的顶级代码
(打印、变量赋值、函数的定义等)都会执行 - 装饰器在导⼊时或运行时
立即执行
,函数的装饰器
,优先级⽐函数⾼,⽽类的装饰器
- 模块中的函数或者是类(对象)中的⽅法(除了装饰器),仅仅在
调⽤时(运行时)
- 无论在导入时还是运行时,
模块只会导⼊⼀次(最先导入的)
,解释器如果发现模块已经被导⼊,则跳过,继续向后执⾏(避免写出互相导⼊的死循环代码)
-------------------------------------------------
# import_runtime.py start
-------------------------------------------------
# 这里是模块的顶级代码(模块导入/运行时会运行)
print("module {} start.".format(__name__))
y = 12
print('y is {}'.format(y))
# Class 定义是模块的顶级代码(模块导入/运行时会运行)
class ClassX():
# 这里是类的顶级代码(模块导入/运行时会运行)
x = 5
print('x is {}'.format(x))
print("ClassX body start.")
def __init__(self):
print("ClassX __init__")
def __del__(self):
print("ClassX __del__")
def method(self):
print("ClassX method.")
def func_x():
print("func_x.")
# 类装饰器
def deco_class(cls):
print("decorator for class.")
print("decorate {}.".format(cls.__name__))
return cls
# 函数装饰器
def deco_func(func):
print("decorator for function.")
print("decorate {}.".format(func.__name__))
return func
@deco_class # 这里是类装饰器(模块导入/运行时会运行)
class ClassY():
print("ClassY body start.")
def __init__(self):
print("ClassY __init__.")
def __del__(self):
print("ClassY __del__.")
@deco_func # 这里是函数装饰器(模块导入/运行时会运行)
def method(self):
print("ClassY method.")
@deco_class # 这里是类装饰器(模块导入/运行时会运行)
class ClassZ():
print("ClassZ body start.")
@deco_func # 这里是函数装饰器(模块导入/运行时会运行)
def func_y():
print("function func_y.")
if __name__ == "__main__":
# pass
x = ClassX()
x.method()
func_x()
y = ClassY()
y.method()
func_y()
print("module {} end.".format(__name__))
-------------------------------------------------
# import_runtime.py end
-------------------------------------------------
module import_runtime start.
y is 12
x is 5
ClassX body start.
ClassY body start.
decorator for function.
decorate method.
ClassZ body start.
decorator for class.
decorate ClassZ.
decorator for class.
decorate ClassY.
decorator for function.
decorate func_y.
module import_runtime end.
-------------------------------------------------
# 上面输出结果为导入时(__main__ 换成模块名 import_runtime )的输出
-------------------------------------------------
module __main__ start.
y is 12
x is 5
ClassX body start.
ClassY body start.
decorator for function.
decorate method.
ClassZ body start.
decorator for class.
decorate ClassZ.
decorator for class.
decorate ClassY.
decorator for function.
decorate func_y.
ClassX __init__
ClassX method.
func_x.
ClassY __init__.
ClassY method.
function func_y.
module __main__ end.
ClassX __del__
ClassY __del__.
-------------------------------------------------
# 上面输出结果为运行时(__main__)的输出
# 运行时 = 导入时+main+析构,模块的顶级代码都会执行
-------------------------------------------------
五、pip 包管理器的使用及其下载源的更改
1、pip 包管理器的使用
-
PyPI(Python Package Index)
是 python 官方的第三方库的仓库,PyPI 推荐使用pip 包管理器
来下载第三方库 - 安装 pip:
sudo apt-get install python-pip
,安装 pip3:sudo apt-get install python3-pip
# pip 使用格式
pip <command> [options] package_name
# 安装指定版本的包
pip install package_name==1.9.2
# 更新指定的包
pip install --upgrade package_name
# 卸载指定的包
pip uninstall package_name
# 查看所安装包的详细信息
pip show package_name
# 查看所有安装的包
pip list
# 查看帮助
pip --help
2、pip 下载源的更改
# 升级 pip
pip3 install --upgrade pip
eg:pip3 install opencv-python
# 国内常用的镜像
https://pypi.douban.com/simple/ # 豆瓣
http://mirrors.aliyun.com/pypi/simple/ # 阿里
https://pypi.tuna.tsinghua.edu.cn/simple # 清华
https://pypi.mirrors.ustc.edu.cn/simple/ # 中国科学技术大学
http://pypi.hustunique.com/simple/ # 华中理工大学
# 1、临时使用,添加 “-i” 或 “--index” 参数
pip install -i https://pypi.douban.com/simple/ flask --trusted-host pypi.douban.com
pip install --extra-index-url https://pypi.douban.com/simple/ flask # 报错时可尝试加 --extra-index-url
pip3 install --ignore-installed PyYAML -i https://pypi.tuna.tsinghua.edu.cn/simple
# PyYAML 安装,报错无法卸载旧版本,尝试加参数 --ignore-installed 或 --force-reinstall 解决
# 2、linux 下永久生效的配置方法
cd $HOME
mkdir .pip
cd .pip
sudo vim pip.conf
# 在里面添加,trusted-host 选项为了避免麻烦是必须的,否则使用的时候会提示不受信任
[global]
index-url=https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host=pypi.tuna.tsinghua.edu.cn
disable-pip-version-check=true
timeout = 6000
# 3、window 下永久生效的配置方法
# a、进入如下目录(没有此目录或文件就自己创建下)
C:\Users\username\AppData\Local\pip
或
C:\Users\username\pip
# b、创建 “pip.ini” 文件(注意:以UTF-8 无BOM格式编码),添加如下内容
[global]
index-url=https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host=pypi.tuna.tsinghua.edu.cn
disable-pip-version-check=true
timeout = 6000
六、默认 py2 和 py3 的切换
# 1、Create list of alternatives for python
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 2
# 2、Check the python list
update-alternatives --list python
# 3、update alternative to select required python version
sudo update-alternatives --config python
文件相关(os、os.path、 glob模块)、存储对象(pickle、cPickle模块)
记录日志(logging 模块)
时间与日期(time&timeit 模块)
正则表达式(re 模块)
数学、随机数生成等(使用numpy 或 scipy 等第三方库)
循环器(itertools)
数据库(sqlite3)
线程同步(threading包)
多进程初步(multiprocessing包)
八、Python 常用第三方库(博客总结)
- Anaconda:包管理
- Ipython & Jupyter Notebook:快速验证思路、分享和演示
- OpenCV:图像处理
- Numpy:快速向量化运算
- Scipy:科学计算
- Pandas:序列化数据的分析处理
- Matplotlib:类似 Matlab 的画图工具
- Scikits:scikits-learn 机器学习和 scikits-image 图像处理
- Xgboost
九、参考资料
1、python文件目录下的__init__文件2、python importlib 用法小结