在 Python 中映射模块导入以便于重构

Posted

技术标签:

【中文标题】在 Python 中映射模块导入以便于重构【英文标题】:Mapping module imports in Python for easy refactoring 【发布时间】:2011-04-04 04:10:47 【问题描述】:

我有一堆 Python 模块想要清理、重组和重构(有一些重复的代码,一些未使用的代码......),我想知道是否有工具可以制作出使用哪个模块的地图还有哪个模块。

理想情况下,我想要这样的地图:

main.py
 -> task_runner.py
  -> task_utils.py
  -> deserialization.py
   -> file_utils.py
 -> server.py
  -> (deserialization.py)
  -> db_access.py

checkup_script.py
re_test.py
main_bkp0.py
unit_tests.py

... 这样我就可以知道我可以首先开始移动哪些文件(file_utils.py,db_access.py),我的 main.py 没有使用哪些文件,因此可以删除,等等。(I' m 实际上使用了大约 60 个模块)

编写一个执行此操作的脚本可能不会非常复杂(尽管导入处理有不同的语法),但我也希望我不是第一个想要这样做(如果有人为此制作了一个工具,它可能包含其他简洁的功能,例如告诉我哪些类和函数可能未使用)。

你知道任何帮助代码重组的工具(甚至是简单的脚本)吗?

你知道我想要做什么的更准确的术语吗?代码重组?

【问题讨论】:

【参考方案1】:

Python 的modulefinder 就是这样做的。编写将这些信息转换为导入图的脚本非常容易(您可以使用例如graphviz 进行渲染):这是clear explanation。还有 snakefood 可以为您完成所有工作(也使用 AST!)

您可能需要查看pylintpychecker 以了解更多常规维护任务。

【讨论】:

谢谢!我通过无耻地窃取您发送的解释中的代码并戳它直到它给出了我需要的图表,设法得到了我正在寻找的地图。我还使用模块查找器列出了我没有使用的模块(超过一半),所以我可以直接核对它们而不再考虑它们。我也得到了 pylint,但还没有玩太多。【参考方案2】:

编写一个执行此操作的脚本可能不会很复杂(尽管导入处理有不同的语法),

这是微不足道的。有importfrom module import。要处理的两种语法。

你知道我想要做什么的更准确的术语吗?代码重组?

设计。它被称为设计。是的,您正在重构现有设计,但是...

第一条规则

不要以现有的东西开始设计工作。如果你这样做了,你只会“在边缘”做一些微小的,有时甚至是无关紧要的改变。

规则二

如果你更聪明的话,应该开始设计工作。广泛而清晰地思考您真正应该做什么。忽略你的所作所为。

规则三

使用正确的包和模块架构从头开始(或者像某些人所说的那样de novo)。

为此创建一个单独的项目。

第四条

先测试。为您的新架构编写单元测试。如果您有现有的单元测试,请将它们复制到新项目中。修改导入以反映新架构并重写测试以表达您光荣的新简化。

所有测试都失败了,因为您没有移动任何代码。这是一件好事。

第五条

最后将代码移入新结构。测试通过后停止移动代码。

顺便说一句,您不需要分析导入来执行此操作。您只是使用grep 来查找模块和类。旧进口和旧进口之间的纠结关系无关紧要,无需分析。你把它扔掉了。您不需要比 grep 更智能的工具。

如果有移动代码的冲动,你必须非常自律。 (1) 您必须有失败的测试,然后 (2) 您可以移动一些代码以通过失败的测试。

【讨论】:

+1。并且不要忘记 import module.submod as submod 作为变体。它一直在我身上长大。 @aaronasterling:在我看来还是r"\s*import\s+.*" 从头开始重写通常是不切实际的,并且可能导致永远的毁灭公爵综合症。【参考方案3】:

chuckmove 是一个工具,可让您在整个源代码树中递归地重写导入以引用模块的新位置。

chuckmove --old sound.utils --new media.sound.utils src

...这会下降到 src,并将导入 sound.utils 的语句重写为导入 media.sound.utils。它支持所有 Python 导入格式。 IE。 from x import yimport x.y.z as w

【讨论】:

【参考方案4】:

Modulefinder 可能不适用于 Python 3.5*,但 pydeps 运行良好:

安装:

sudo apt install python-pygraphviz
pip install pydeps

然后,在你要映射的目录中,

pydeps --max-bacon=0 .

..创建最大深度的地图。

*Python 3.5 而非 3.6 中的一个问题导致了 modulefinder 的问题,类似于this

【讨论】:

以上是关于在 Python 中映射模块导入以便于重构的主要内容,如果未能解决你的问题,请参考以下文章

hadoop streaming 中跑python程序,自定义模块的导入

python 关于 不同模块内类的变量继承和包的模块导入的一些感悟

在 ES 模块(Node.js)中导入 JSON 文件

python导入类

用于命令行脚本和导入模块的 Python“模板”模块

从boost python模块中的pyside导入类?