为什么全球变数是邪恶的?

2024-06-02 06:57:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图找到一个好的来源来解释为什么在python中(以及在一般编程中)使用global被认为是不好的实践。有人能给我指一个还是解释一下?


Tags: 编程来源global
3条回答

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

此外,如果你考虑其他人阅读你的代码(开源社区、同事等),他们将很难理解全局变量的设置位置,与单独的函数相比,全局变量的功能可以通过读取函数定义本身来确定。

(可能)违反纯函数定义

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

  1. 如果给定相同的参数值,函数总是计算相同的结果值。函数结果值不能依赖于程序执行过程中或程序的不同执行之间可能更改的任何隐藏信息或状态,也不能依赖于来自I/O设备的任何外部输入(通常见下文)。
  2. 对结果的评估不会导致任何语义上可观察到的副作用或输出,例如可变对象的变异或输出到I/O设备。

如果不同时作为外部代码使用全局变量,则可能会导致意外的结果,这至少违反了上面的一个。

纯函数的另一个明确定义是:“纯函数是一个函数,它将其所有输入作为显式参数并将其所有输出作为显式结果”[1]。拥有全局变量违背了纯函数的概念,因为输入和输出(全局变量)中的一个没有被显式地给出或返回。

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

此外,如果考虑单元测试和F.I.R.S.T原则(Fast测试,I独立测试,R可接受的,Self验证和Timely),则可能违反独立测试原则(这意味着测试不相互依赖)。

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

全局作为常量

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

我不认为不应该用地球仪。但是,如果使用它们,作者应该考虑一些原则(上面提到的原则,以及其他软件工程原则和良好实践),以获得更干净、几乎没有错误的代码。

这与Python无关;全局变量在任何编程语言中都是不好的。

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

它们不好的原因是它们允许函数有隐藏的(不明显的、令人惊讶的、难以检测的)副作用,导致复杂性的增加,可能导致Spaghetti code

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

总之,你的问题可以通过多种方式得到答案,所以你最好的选择就是谷歌“为什么全球变量不好”。一些例子:

如果你想更深入地了解为什么会产生副作用,以及许多其他启发性的事情,你应该学习函数式编程:

是的,在理论上,,全局(和一般的“状态”)是邪恶的。实际上,如果您查看python的packages目录,您会发现那里的大多数模块都是从一堆全局声明开始的。很明显,人们对他们没有问题。

特别是对于python,globals的可见性仅限于一个模块,因此没有“真正的”globals会影响整个程序——这使得它们的危害更小。另一点:这里没有const,因此当需要常量时,必须使用全局。

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

cache = {}

def foo(args):
    global cache

    cache[args] = ...

这使得全局操作更容易追踪。

相关问题 更多 >