python - 可视化 Python 函数流(例如树或概念图)
问题描述
我以一种非常随意的方式自学了 python。所以我的问题可能不会很pythonic。
当我在类中编写函数时,我经常忘记每个函数的作用。我确实尝试正确命名它们。但是,它们有时仍然是代码的较小部分,在哪些函数中放置它们似乎是任意的。因此,每当我想进行更改时,我仍然需要检查整个代码,以便弄清楚我的函数实际上是如何流动的。
据我了解,我们有对象和函数,这些是我们构建代码的单元。但这只会给你一个扁平的结构。它不允许您在多个级别上进行任何类型的嵌套,例如在树形图中。特别是,我的文件中的代码不会自动浇灌自己,因此首先调用的函数会自动在顶部进一步向上调用,而辅助函数会自动在文档中进一步向下,甚至嵌套。
事实上,即使能够在视觉上将低阶子例程嵌套在调用它的高阶函数“内部”似乎也很有帮助。但这不是 Python 语法支持的东西。(另外,这还不够,因为一个子例程可能会被几个高阶函数使用。)
我想将代码中的所有函数可视化为树或概念图会很有用:
每个函数都是一个点。并通过箭头显示调用顺序。这样,我也可以很容易地看到哪些函数更中心化,哪些函数更离群,甚至是孤立的。
然而,也许这甚至不是另一种工具的情况。也许这更多是我不了解正确编码的情况。也许我可以做一些不同的事情,以便在不需要其他工具的情况下对我的程序如何工作有一种直观的了解。
解决方案
首先,我不太清楚为什么不经常问这个问题。阅读代码一点也不直观!我们应该能够很好地可视化一个过程或功能的演变,以便接近每个人都能够理解它的行为。在 60 年代左右,人们必须合理地确定他们的程序会运行,因为访问计算机需要时间。今天我们执行或编译我们的程序,运行测试(如果有的话),并立即知道它是否有效。发生的事情是现在的脑力劳动减少了,我们在头脑中执行的代码少了一点,而计算机多了一点。但是我们仍然必须考虑程序在执行过程中的行为以便进行调试。对于未来,如果计算机能够告诉我们程序的行为方式,那就太好了。
您建议将程序的一种树视为一种果断,毕竟抽象语法树实际上是一棵树,但我认为这不是我们在可视化系统时应该花费的精力. 更可取的是,如果我们可以查看问题如何随时间改变其中间数据结构的交互式视图。
目前,我们有调试器——但这类似于通过询问一个函数在许多值上是什么来查看问题,而我们更愿意查看它的图表。很多编程都是通过做一些你认为正确的事情来完成的,观察行为是否正确,如果它不正确,那么我们通过反应和纠正所述行为来进行修改。
Bret Victor 在他的文章Learnable Programming中讨论了这个话题。我强烈推荐它,即使它现在对您没有帮助,也许您可以通过使这些想法更普遍来帮助其他人。
之后,然后到我告诉你你现在可以做什么的地方。Robert C. Martin 在他的《清洁代码》一书中提出了结构化代码,就像报纸的布局方式一样。
想想一篇写得很好的报纸文章。你竖着读。在顶部,您希望有一个标题,它将告诉您故事的内容,并允许您决定是否要阅读它。第一段为您提供了整个故事的概要,隐藏了所有细节,同时为您提供了粗略的概念。随着您继续向下,详细信息会增加,直到您拥有所有日期、姓名、报价、声明和其他细节。
建议是自上而下地组织您的程序,其中较高级别的程序调用中级程序,而中级程序又调用较低级别的程序。在任何地方,很明显(1)您处于适当的抽象级别,并且(2)您正在查看实现您想要修改的行为的程序部分。
这意味着将状态存储在它所属的级别,并将其暴露在其他任何地方。过程应该只取它们需要的参数,因为更多的参数意味着你在推理代码时也必须考虑更多的参数。
这是将程序分解为更小的程序的主要原因。例如,这里有一些我之前写过的代码。它并不完美,但是如果您想更改任何内容,您可以非常清楚地看到您需要进入程序的哪个部分。
当然,高阶程序列在任何其他程序之前。我告诉你我要做什么,然后再告诉你我是怎么做的。
function formatLinks(matches, stripped) {
let formatted_links = []
for (match of matches) {
let diff = difference(match, stripped)
if (isSimpleLink(diff)) {
formatted_links.push(formatAsSimpleLink(diff))
} else if (hasPrefix(diff)) {
formatted_links.push(formatAsPrefixedLink(diff))
} else if (hasSuffix(diff)) {
formatted_links.push(formatAsSuffixedLink(diff))
}
}
// There might be multiple links within a word
// in which case we join them and strip any duplicated parts
// (which are otherwise interpreted as suffixes)
if (formatted_links.length > 1) {
return combineLinks(formatted_links)
}
// Default case
return formatted_links[0]
}
如果 JavaScript 是一种类型语言,并且如果我们可以看到代码中做出的决策的图像,作为输入和时间的一个因素,这可能会更好。
我认为Quokka.js和VS Code Debug Visualizer都在这个领域做着有趣的工作。
推荐阅读
- hyperlink - 如何使用谷歌电子表格使用公式检查损坏的链接
- hadoop - Pig:如何检索两个连续元组之间的差异。(整数类型)
- javascript - javascript - 如何使用对象中的窗口获取变量的值作为变量
- delphi - 开始触摸和结束触摸事件 Delphi
- php - Codeigniter 函数中的特殊字符打印
- jquery - 使用 jquery 从嵌套 json 中获取键名
- excel - 当列中的数字发生变化时,Excel 2013 颜色填充
- php - 在下载 zip 文件之前打印 html
- asp.net-core - 自定义 ASP.Net Core JSON 模型绑定器
- spring-boot - 让 Tomcat 7 在远程 CentOS 7.5 上工作