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

时间:2013-10-03 11:44:57

标签: python global-variables side-effects

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

4 个答案:

答案 0 :(得分:113)

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

但是,全局常量在概念上与全局变量不同;全局常量完全无害。只是在Python中没有强制差异,只有按惯例CONSTANTS_CAPITALIZEDglobals_are_not

它们不好的原因是它们允许函数隐藏(非显而易见,令人惊讶,难以察觉)的副作用,导致复杂性增加,可能导致Spaghetti code

然而,即使在函数式编程中,对于全局状态的合理使用也是可接受的(就像本地状态和可变性一样),无论是算法优化,复杂性降低,缓存和存储,还是源自主要命令式代码库的移植结构的实用性。

总而言之,您的问题可以通过多种方式得到解答,因此您最好的选择就是谷歌"为什么全局变量不好?#34;。一些例子:

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

答案 1 :(得分:27)

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

特别是对于python,全局变量的可见性仅限于一个模块,因此没有影响整个程序的“真正”全局变量 - 这使得它们的危害性降低。另一点:没有const,所以当你需要一个常数时,你必须使用全局。

在我的练习中,如果我碰巧修改了函数中的全局函数,我总是用global声明它,即使技术上不需要它,如:

cache = {}

def foo(args):
    global cache

    cache[args] = ...

这使得全局变量的操作更容易被追踪。

答案 2 :(得分:8)

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

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

(可能)违反纯函数定义

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

  1. 函数始终在给定相同参数值的情况下评估相同的结果值。函数结果值不能依赖于程序执行过程中或程序执行不同时可能发生的任何隐藏信息或状态,也不依赖于I / O设备的任何外部输入(通常见下文)。
  2. 评估结果不会导致任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I / O设备。
  3. 如果不是外部代码,全局变量至少违反了上述一项,因为外部代码可能会导致意外结果。

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

    (可能)违反单位测试F.I.R.S.T原则

    此外,如果您考虑单元测试和FIRST原则( F ast测试, I 独立测试, R 可重复, S elf-Validating和 T imely)可能会违反独立测试原则(这意味着测试不会相互依赖)。

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

    Globals as constants

    另一方面,正如其他人已经提到的那样,如果全局变量被用作"常数"由于语言不支持常量,因此变量可能略好一些。但是,我总是喜欢使用类和#34;常数"作为类成员,根本不使用全局变量。如果您有一个代码,两个不同的类需要共享一个全局变量,那么您可能需要重构您的解决方案并使您的类独立。

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

答案 3 :(得分:3)

它们是必不可少的,屏幕就是一个很好的例子。但是,在多线程环境中或涉及许多开发人员的情况下,实际上常常会出现这样的问题:谁(确实)设置或清除了它?根据体系结构的不同,分析成本高昂且经常需要进行分析。虽然读取全局变量可以正常,但必须控制对它的写入,例如通过单个线程或线程安全类。因此,全球变量引发了对自身被认为是邪恶的后果可能导致高昂的开发成本的恐惧。因此,一般来说,保持全球变量数量较低是一种很好的做法。