介绍
一个 python project 中往往包含很多 .py 文件。python文件中又会包含很多函数,函数之间相互传参和调用。如果遇到代码行数很多的情况,我们阅读起来就会有困难。那么有什么办法可以解决这个困难呢?
我们可以考虑采取可视化的方法将代码调用关系用图的方法表示出来。 pycallgraph是一种适用于python代码的动态调用分析工具。当然要想实现可视化还需要安装graphviz。graphviz 是一个图形可视化工具,可以将调用关系表示为图的形式。
Graphviz 安装
首先给出 graphviz 的官网链接:http://www.graphviz.org/download/
亲测装了不好用,而且下载缓慢
看了几个教程,Graphviz-2.38比较好适配,👇提供免费下载。
安装包:https://download.csdn.net/download/weixin_45080292/85428385
傻瓜安装,安装完成后记得添加环境变量
加环境变量
1 添加系统环境变量
建立变量名GRAPHVIZ_DOT
值为安装的路径 F:\Install_path\Graphviz_win64\bin\dot.exe
2 设置环境变量 在用户环境变量添加以下一个变量
建立变量名 GRAPHVIZ_INSTALL_DIR,
值为如F:\Install_path\Graphviz_win64
3 在系统环境变量 建立变量名PATH中添加Graphviz的bin目录路径,
如 F:\Install_path\Graphviz_win64\bin
安装完成后可在cmd窗口输入:dot -v 查看版本信息,如果可以显示表示已经配置成功。
pycallgraph安装
pip install pycallgraph
说明,挂在VPN导致失败,退出VPN即可下载,不需要镜像。
错误情况:
pip intsall 安装报错 ERROR: Could not find a version that satisfies the requirementi
问题的产生: 我之前就遇到了这个问题,第一次出现问题的原因是因为我先使用 pip uninstall 包名x,然后在使用 pip install install 包名x 然后出现的这个问题 那个没有解决之后重装了anaconda.这里出现问题是因为我运行程序的时候下载预训练模型的时候感觉网速比较慢中途终止了程序,然后开启的 vpn (重点重点 圈起来要考的) 加速, 然后再次使用pip install 的时候遇上了如上的我问题。 所以这次我不想再次重装anaconda. 要处理他。
首先我这两次出现这个问题都是因为开启的代理服务器 VPN, 所以只要把刚刚所开启的代理服务器关闭即可解决。
处理完这些打开pycharm准备安装pycallgraph,又出现了终端打不来
解决办法:
将shell path 改为本机终端所在的路径
如果不知道自己powershell的路径,可以在Cortana这边搜索powershell,然后打开文件位置,再右击快捷方式打开文件位置,如下两张图。
填好以后重启下pycharm,问题解决。
实践
你的程序 只有你的操作 使用了某个函数,才能显示在流图中。用户没有使用的功能则不会出现在流图中。
库文件调用
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
from pycallgraph import Config
from pycallgraph import GlobbingFilter
主函数
def main():
# 你的主函数代码。
if __name__ == "__main__":
config = Config()
# 关系图中包括(include)哪些函数名。
#如果是某一类的函数,例如类gobang,则可以直接写'gobang.*',表示以gobang.开头的所有函数。(利用正则表达式)。
config.trace_filter = GlobbingFilter(include=[
'方法1','方法2'
])
# 关系图中不包括(exclude)哪些函数。(正则表达式规则)
# config.trace_filter = GlobbingFilter(exclude=[
# 'pycallgraph.*',
# ])
graphviz = GraphvizOutput()
graphviz.output_file = 'graph.png'
with PyCallGraph(output=graphviz, config=config):
main()
如果不需要特别备注需要和不需要,只要将config.trace_filter方法删去即可。
实例
import numpy as np
import matplotlib.pyplot as plt
## graph
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
from pycallgraph import Config
from pycallgraph import GlobbingFilter
# from pycallgraph import Config
# from pycallgraph import PyCallGraph
# from pycallgraph.output import GraphvizOutput
# from werkzeug.datastructures import ImmutableMultiDict
# from app.main.views import do_all_copy
def main():
delta_t = 0.1 # 每秒钟采一次样
end_t = 7 # 时间长度
time_t = end_t * 10 # 采样次数
t = np.arange(0, end_t, delta_t) # 设置时间数组
u = 1 # 定义外界对系统的作用 加速度
x = 1 / 2 * u * t ** 2 # 实际真实位置
v_var = 1 # 测量噪声的方差
# 创建高斯噪声,精确到小数点后两位
v_noise = np.round(np.random.normal(0, v_var, time_t), 2)
X = np.mat([[0], [0]]) # 定义预测优化值的初始状态
v = np.mat(v_noise) # 定义测量噪声
z = x + v # 定义测量值(假设测量值=实际状态值+噪声)
A = np.mat([[1, delta_t], [0, 1]]) # 定义状态转移矩阵
B = [[1 / 2 * (delta_t ** 2)], [delta_t]] # 定义输入控制矩阵
P = np.mat([[1, 0], [0, 1]]) # 定义初始状态协方差矩阵
Q = np.mat([[0.001, 0], [0, 0.001]]) # 定义状态转移(预测噪声)协方差矩阵
H = np.mat([1, 0]) # 定义观测矩阵
R = np.mat([1]) # 定义观测噪声协方差
X_mat = np.zeros(time_t) # 初始化记录系统预测优化值的列表
for i in range(time_t):
# 预测
X_predict = A * X + np.dot(B, u) # 估算状态变量
P_predict = A * P * A.T + Q # 估算状态误差协方差
# 校正
K = P_predict * H.T / (H * P_predict * H.T + R) # 更新卡尔曼增益
X = X_predict + K * (z[0, i] - H * X_predict) # 更新预测优化值
P = (np.eye(2) - K * H) * P_predict # 更新状态误差协方差
# 记录系统的预测优化值
X_mat[i] = X[0, 0]
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置正常显示中文
plt.plot(x, "b", label='实际状态值') # 设置曲线数值
plt.plot(X_mat, "g", label='预测优化值')
plt.plot(z.T, "r--", label='测量值')
plt.xlabel("时间") # 设置X轴的名字
plt.ylabel("位移") # 设置Y轴的名字
plt.title("卡尔曼滤波示意图") # 设置标题
plt.legend() # 设置图例
plt.show() # 显示图表
if __name__ == "__main__":
config = Config()
# 关系图中包括(include)哪些函数名。
# 如果是某一类的函数,例如类gobang,则可以直接写'gobang.*',表示以gobang.开头的所有函数。(利用正则表达式)。
# config.trace_filter = GlobbingFilter(include=[
# 'draw_chessboard',
# 'draw_chessman',
# 'draw_chessboard_with_chessman',
# 'choose_save',
# 'choose_turn',
# 'choose_mode',
# 'choose_button',
# 'save_chess',
# 'load_chess',
# 'play_chess',
# 'pop_window',
# 'tip',
# 'get_score',
# 'max_score',
# 'win',
# 'key_control'
# ])
# 该段作用是关系图中不包括(exclude)哪些函数。(正则表达式规则)
# config.trace_filter = GlobbingFilter(exclude=[
# 'pycallgraph.*',
# '*.secret_function',
# 'FileFinder.*',
# 'ModuleLockManager.*',
# 'SourceFilLoader.*'
# ])
graphviz = GraphvizOutput()
graphviz.output_file = 'graph.png'
with PyCallGraph(output=graphviz, config=config):
main()
结果图:
使用pycallgraph这个工具,可以帮助我们更好的入手去分析一个全新的软件包。通过了解各个模块之间的调用关系,我们还可以比较直观的梳理出相关的架构图,带着架构的思维去逐层的分析相应的软件及其实现的方式。