为什么全局变量是邪恶的?

Lar*_*gas 100 python side-effects global-variables

我试图找到一个很好的来源,解释为什么global在python(以及一般的编程)中使用被认为是不好的做法.有人可以指点我或解释一下吗?

Eri*_*lun 127

这与Python无关; 全局变量在任何编程语言中都很糟糕.

但是,全局常量在概念上与全局变量不同 ; 全局常量非常好用.只是在Python中没有语法差异.

它们不好的原因是它们允许函数隐藏(如"非显而易见"和"未声明")并因此难以理解副作用.此外,这可能导致Spaghetti代码.

此外,有限/可控/有意识地使用全局变量是可以接受的,就像本地状态,即可变变量,在功能编程中可接受的,无论是出于性能原因还是简单性,还是用于缓存/记忆.

但是,当然,你的问题有很多答案,所以你最好的选择就是谷歌"为什么全局变量都不好".一些例子:

如果你想深入了解副作用的原因,以及许多其他有启发性的东西,你应该学习功能编程:


geo*_*org 30

是的,从理论上讲,全局(和一般的"状态")是邪恶的.实际上,如果你查看python的packages目录,你会发现大多数模块都以一堆全局声明开头.显然,人们对他们没有任何问题.

Specifically to python, globals' visibility is limited to a module, therefore there are no "true" globals that affect the whole program - that makes them a way less harmful. Another point: there are no const, so when you need a constant you have to use a global.

In my practice, if I happen to modify a global in a function, I always declare it with global, even if there technically no need for that, as in:

cache = {}

def foo(args):
    global cache

    cache[args] = ...
Run Code Online (Sandbox Code Playgroud)

This makes globals' manipulations easier to track down.

  • @CorleyBrigman:单例类实际上经常遇到通常归因于全局变量的相同问题:) (9认同)
  • python模块的可见性不仅限于模块.它们在整个解释器中都可用,并且(这里是重要的)更改会影响整个解释器.它不像您创建实例的字符串...就像修改所有字符串实例一样.猴子修补气味. (4认同)
  • 在许多方面,python中的模块类似于单例类,模块全局变量类似于类属性. (3认同)
  • 大多数模块不是从定义全局 _except_ 常量开始的。全局变量不好意味着 _variables_ / _global state_ 不是常量。 (2认同)
  • 使用全局变量是一个可怕的想法,一个原因可能是无法正确测试更新某些“某处”存在的任意字典的函数。带有全局变量的代码库实际上不能被证明是有效的。 (2认同)

Raf*_*ael 10

关于该主题的个人观点是,在函数逻辑中使用全局变量意味着某些其他代码可以改变该函数的逻辑和预期输出,这将使调试非常困难(特别是在大项目中)并且将使测试更难同样.

此外,如果您考虑其他人阅读您的代码(开源社区,同事等),他们将很难尝试了解全局变量的设置位置,已更改的位置以及对此全局变量的期望通过读取函数定义本身可以确定其功能的隔离函数.

(可能)违反Pure Function定义

我相信一个干净且(几乎)无错误的代码应该具有尽可能纯的函数(参见纯函数).纯函数是具有以下条件的函数:

  1. 给定相同参数值的情况下,该函数始终评估相同的结果值.功能结果值不能依赖于程序执行过程中或程序执行不同时可能发生的任何隐藏信息或状态,也不依赖于I/O设备的任何外部输入(通常见下文).
  2. 对结果的评估不会导致任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I/O设备.

由于外部代码可能导致意外结果,因此全局变量违反了上述至少一项(如果不是两者).

纯函数的另一个明确定义:"纯函数是一个函数,它将所有输入作为显式参数,并将其所有输出作为显式结果生成." [1].全局变量违反了纯函数的概念,因为输入可能没有明确地给出或返回输出之一(全局变量).

(可能)违反单位测试FIRST原则

此外,如果你考虑单元测试和FIRST原则(F ast测试,我独立测试,R epeatable,S elf-Validating和T imely)可能会违反独立测试原则(这意味着测试不依赖于彼此).

拥有一个全局变量(并非总是)但在大多数情况下(至少我目前所见)是准备并将结果传递给其他函数.这也违反了这一原则.如果以这种方式使用了全局变量(即函数X中使用的全局变量必须首先在函数Y中设置),则意味着要对单元测试函数X进行首先运行测试/运行函数Y.

全局作为常数

另一方面,正如其他人已经提到的,如果全局变量被用作"常量"变量,则可能稍微好一点,因为该语言不支持常量.但是,我总是喜欢使用类并将"常量"作为类成员,而根本不使用全局变量.如果您有一个代码,两个不同的类需要共享一个全局变量,那么您可能需要重构您的解决方案并使您的类独立.

我不相信不应该使用全局变量.但是如果使用它们,作者应该考虑一些原则(上面提到的原则和其他软件工程原理和良好实践),以获得更清晰,几乎没有错误的代码.