Python全局关键字与Pylint W0603
Pylint W0603 的意思是:
使用 global 语句。 当你用 "global" 语句来更新一个全局变量时,就会出现这个提示。Pylint 只是想让你少用这种方式。这并不是说你不能用它!
我想知道为什么会这样?有没有更符合 Python 风格的方法来在函数内部修改不可变的模块级变量?是不是建议把它们放在像字典这样的可变变量里?或者干脆把整个模块变成一个类?
在我看来,当变量被建议为“私有”(前面加上 _ 或 __)时,这个警告应该消失。
4 个回答
在Python中,如果一个模块共享全局数据,那它基本上就是一个单例模式。你可以用一个singleton
类来实现同样的效果,或者问问自己,真的有必要使用单例吗?如果你不需要单例,那就用普通的类(实例)就可以了。如果你确实需要单例,可以去谷歌或者搜索StackOverflow,看看哪种模式最适合你。也许你确实想用模块——全局变量是有它存在的理由的——否则Guido早就把它从语言中去掉了。不过,这个理由其实是比较小众的……
我会把这个:
the_file = None
def open_the_file(fname):
global the_file
the_file = open(fname)
def write_to_the_file(data):
the_file.write(data)
open_the_file("boo")
write_to_the_file("Hi!")
换成这个:
class FileProgram(object):
def __init__(self):
self.the_file = None
def open_the_file(fname):
self.the_file = open(fname)
def write_to_the_file(data):
self.the_file.write(data)
if __name__ == "__main__":
prog = FileProgram()
prog.open_the_file("boo")
prog.write_to_the_file("Hi!")
你可能会说:“这对我简单的任务来说太复杂了!” 好吧,那就别让pylint检查你的程序。你不能指望pylint理解你的程序太小,不需要用好的结构。
全局变量的随意使用会让维护变得非常麻烦,因为它们会让你很难追踪程序的执行流程。有时候你会遇到奇怪的错误,因为某个模块在另一个模块改变变量值之前就读取了这个变量并根据它的值进行了操作(这可能是因为在某个不相关的第三方模块中调换了两个导入语句的位置)。想了解更多,可以看看维基百科关于全局变量的介绍。
这就是为什么我认为你应该尽量避免使用可变的全局变量的原因,也是为什么Pylint会发出警告(其实它应该发出更多警告。检测使用global
关键字只是发现其中一些问题的简单方法)。
别误会我的意思:我并不是说你绝对不能使用全局变量。只是建议你尽量少用。其实在Python中,有很多合理的全局变量使用场景。只要你遇到的W0603警告不超过几个,应该就没问题。
我曾经在Logilab工作过(这个公司维护Pylint),他们曾经接手维护一段超过5万行的Python代码,这段代码中有大量重复的部分和100多个可变的全局变量。这真是个噩梦。
为了避免使用全局变量,可以考虑以下解决方案:
- 给需要访问变量的函数添加参数
- 使用类属性
- 使用实例属性(通过将需要的值传递给类的构造函数)
- 将可变的全局值集中在一个配置对象中,这个对象在程序启动时只实例化一次(可以通过环境变量、命令行、配置文件等方式),之后不再修改。