如何跟踪Python源文件的变化?
我正在学习Python,遇到一个需要改变函数行为的情况。我之前是Java程序员,所以在Java的世界里,如果我修改了一个函数,Eclipse会显示很多Java源文件有错误。这样我就能知道哪些文件需要修改。但是在Python中没有类型,这种情况该怎么处理呢?我现在用的是TextMate2来写Python代码。
目前我在用一种比较笨的方法,就是打开每个Python脚本文件,检查我在哪里使用了那个函数,然后进行修改。但我知道这样处理大项目肯定不行!!!
编辑:举个例子,我在一个Python脚本文件中定义了一个叫做Graph
的类。Graph
有两个对象变量。我在很多脚本文件中创建了很多这个类的对象(每个对象名字都不一样!!!),然后我决定要改一下对象变量的名字!现在我得一个个文件翻看我的代码,重新修改名字,真是太麻烦了 :(. 请帮帮我!
举个例子:文件A
有类C
的对象x,y,z
。文件B
也有类C
的对象xx,yy,zz
。类C
有两个实例变量的名字需要改,从Foo
改成Poo
,从Foo1
改成Poo1
。而且还有很多像A
和B
这样的文件。你会怎么解决这个问题?难道真的要一个个打开文件,搜索x,y,z,xx,yy,zz
,然后逐个改名字吗?!!!
5 个回答
有一个回答专门针对你的修改:
如果你之前的代码是正常工作的,并且不需要修改,那你可以把旧的名字当作新的名字的别名,这样就不会影响到你之前的代码。举个例子:
class MyClass(object): def __init__(self): self.t = time.time() # creating new names def new_foo(self, arg): return 'new_foo', arg def new_bar(self, arg): return 'new_bar', arg # now creating functions aliases foo = new_foo bar = new_bar
如果你的代码需要重写,那就重新写一遍你常用的代码,执行所有的操作,并修正任何出错的地方。你也可以检查一下你的类有没有被导入或实例化。
在文本编辑器里你是无法获得这种功能的。我使用的是Sublime Text 3,我非常喜欢它,但它没有这个功能。不过,它可以通过“跳转到任何地方”(Ctrl+P)快速打开文件和函数,而且它的多重选择/多重编辑功能非常适合小规模的重构任务。
但是,如果你使用的是集成开发环境(IDE),那么JetBrains的PyCharm就有一些很棒的重构工具,可能正是你需要的。
另外,免费的Visual Studio的Python工具(可以查看这里的免费安装选项,它可以使用免费的VS外壳)也有很优秀的重构功能,还有一个很棒的REPL(交互式编程环境)。
我同时使用这三种工具。我大部分时间都在Sublime Text里工作,喜欢用PyCharm进行重构,而PT4VS在复杂原型开发时表现得非常出色。
尽管Python是一种动态类型语言,IDE仍然可以在一定程度上进行代码分析。不过,当然,它的分析能力无法与Java或C#的IDE相比。顺便提一下,如果你是从Java转过来的,可能会接触到JetBrains的IntelliJ,PyCharm的感觉几乎是一样的。
在静态类型语言(比如C#)和动态语言(比如Python)之间,编程风格肯定是不同的。我发现自己更倾向于将代码拆分成小的、可测试的模块。迭代速度更快。在动态语言中,人们对IDE工具的依赖较少,而更依赖于覆盖关键功能的单元测试。如果没有这些单元测试,你在重构时肯定会出问题。
静态类型语言和动态类型语言之间的一个权衡是,动态类型语言不需要太多的类型声明,这样写代码时会轻松一些,但在重构代码和编译时错误检测方面的帮助就少了。虽然一些Python的开发工具提供了一定程度的类型推断和重构帮助,但即使是最好的工具,也无法与静态类型语言的工具相比。
使用动态语言的程序员通常会通过以下一种或多种方式来确保在重构代码时的正确性:
使用
grep
命令查找函数调用的位置,然后进行修复。(如果你想在像Java这样的语言中处理反射,也需要这样做。)启动应用程序,看看哪里出错了。
编写单元测试,如果你还没有的话,使用覆盖率工具确保测试覆盖了整个程序,并在每次修改后运行测试套件,检查一切是否仍然正常。
听起来你只能在一个集成开发环境(IDE)里写代码!
有两个步骤可以让你摆脱IDE的束缚,成为更好的程序员。
为你的代码写单元测试。
学习如何使用grep工具。
单元测试可以帮助你检查代码,确保它始终按照你的预期运行。这样在修改代码时会简单很多。
grep是个很棒的工具,使用 grep -R 'my_function_name' src
这个命令可以找到在 src
目录下所有提到你函数的地方。
另外,可以看看这篇很不错的博客文章: Unix作为IDE。
哎,慢点。你描述的编码过程可不太好扩展。
你到底是怎么改变这个函数的行为的?能具体说说吗?
更新:听起来你是在试图通过拼凑一堆函数和局部变量来实现一个类及其方法——这正是我刚学Python面向对象编程时犯的错误。这里有个问题,就是当某个类内部的类型或类发生变化时,通常不应该影响到类的方法。如果你每10分钟就要重构一次代码,那你肯定是哪里出了问题。退一步想想,应该把代码清晰地分解成对象、方法和数据成员。
(如果你想要更有用的回答,请提供更多具体信息。)
如果你只是改变了输入类型,可能不需要改调用代码。(除非新函数和旧函数做的事情差别很大,那你为什么不直接给它起个不同的名字呢?)
如果你改变了返回类型,而你找不到一个共同的祖先类型或容器(比如元组、序列等)来放返回值,那么是的,你需要改调用它的代码。不过……
……如果这个函数其实应该是一个类的方法,那就直接声明这个类和方法。前面提到的情况说明你的函数其实应该是一个方法,特别是一个多态方法。
了解一下代码异味、反模式,以及你怎么知道自己在处理反模式?。在这里你会找到一些推荐,比如视频“从成瘾中恢复——一个曾经沉迷于Java编程语言的人对Python编程语言简洁优雅的体验。” - Sean Kelly
另外,听起来你想使用测试驱动设计,并添加一些单元测试。
如果你能提供具体信息,我们可以更好地给出建议。