当前位置: 首页 > 知识库问答 >
问题:

为什么全球变量是邪恶的?[闭门]

融建树
2023-03-14

我试图找出为什么使用global在python(以及一般编程)中被认为是不好的做法。有人能解释一下吗?更多信息的链接也将不胜感激。

共有3个答案

焦正德
2023-03-14

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

此外,如果您考虑其他人阅读您的代码(开源社区、同事等),他们将很难尝试了解全局变量设置在何处,在何处发生了更改,以及该全局变量与一个独立函数不同,它的功能可以通过读取函数定义本身来确定。

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

  1. 给定相同的参数值,该函数始终计算相同的结果值。函数结果值不能依赖于任何隐藏信息或状态,这些信息或状态可能在程序执行过程中或程序的不同执行之间发生变化,也不能依赖于来自I/O设备的任何外部输入(通常见下文)

拥有全局变量至少违反了上述两项中的一项,如果不是两项都违反的话,因为外部代码可能会导致意外的结果。

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

此外,如果您考虑单元测试和F.I.R.S.T原理(快速测试、独立测试、可重复、自我验证和及时)可能违反独立测试原则(即测试不依赖于彼此)。

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

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

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

涂泰平
2023-03-14

是的,从理论上讲,全球性(以及“国家”的普遍性)是邪恶的。实际上,如果您查看python的packages目录,您会发现那里的大多数模块都是从一堆全局声明开始的。显然,人们对他们没有问题。

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

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

cache = {}

def foo(args):
    global cache

    cache[args] = ...

这使得globals的操纵更容易被追踪。

汝昀
2023-03-14

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

然而,全局常量在概念上与全局变量不同;全局常量完全无害。在Python中,两者之间的区别纯粹是通过约定:CONSTANTS_ARE_CAPITALIZEDglobals_are_not

全局变量不好的原因是它们使函数具有隐藏的(不明显的、令人惊讶的、难以检测的、难以诊断的)副作用,从而导致复杂性增加,可能导致意大利面代码。

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

总而言之,你的问题可以用很多方法来回答,所以你最好的选择就是谷歌“为什么全球变量不好”。一些例子:

  • 全局变量是坏的-维基百科
  • 为什么Global State如此邪恶?-Software Engineering Stack Exchange
  • 全局变量是坏的吗?

如果您想更深入地了解副作用的原因,以及许多其他启发性的事情,您应该学习函数式编程:

  • 副作用(计算机科学)-维基百科
  • 为什么副作用在函数式编程中被认为是邪恶的?-Software Engineering Stack Exchange
  • 函数编程-维基百科
 类似资料:
  • 问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案能得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 9年前关闭。 在这个问题中,有什么方法可以只接受JTextField中的数值吗?答案之一表明JFormattedTextField存在问题。 我还没有使用过它,但是有人可以

  • 问题内容: 我是一位Java程序员,对公司领域来说是新手。最近,我已经使用Groovy和Java 开发了一个应用程序。我编写的所有代码都使用了大量的静态变量。高级技术人员要求我减少使用的静电数量。我已经在谷歌上搜索了相同的内容,并且发现许多程序员都反对使用静态变量。 我发现静态变量更易于使用。而且我认为它们也是有效的(如果我错了,请纠正我),因为如果我必须对一个类中的一个函数进行10,000次调用

  • 问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案会得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 7年前关闭。 该语言的创造者写的: Go不提供断言。 它们无疑是很方便的,但是我们的经验是程序员将它们用作拐杖,以避免考虑适当的错误处理和报告。正确的错误处理意味着服务器在

  • Lua 是所有脚本语言中最快、最简洁的,我们爱她的快、她的简洁,但是我们也不得不忍受因为这些快、简洁最后带来的一些弊端,我们来挨个数数 module 有多少“邪恶”的吧。 由于 lua_code_cache off 情况下,缓存的代码会伴随请求完结而释放。module 的最大好处缓存这时候是无法发挥的,所以本章的内容都是基于 lua_code_cache on 的情况下。 先看看下面代码: loc

  • 问题内容: 在我用php开发的所有年份中,我一直都听说使用是邪恶的。 考虑以下代码,使用第二个(更优雅)的选项是否有意义?如果没有,为什么? 问题答案: 在将eval()称为纯邪恶时,我会保持谨慎。 动态评估是一个强大的工具,有时可以节省生命。使用eval()可以解决PHP的缺点(请参见下文)。 eval()的主要问题是: 潜在的不安全输入。 传递不受信任的参数是一种失败的方法。确保参数(或其一部

  • 问题内容: Paul Tyma的演讲有以下内容: Executors.newCacheThreadPool邪恶,死死 为什么是邪恶的? 我会冒险猜测:是因为线程数将以无限制的方式增长。因此,如果达到了JVM的最大线程数,被斜线标记的服务器可能会死掉? 问题答案: 问题在于执行器将创建和启动执行执行提交给它的任务所需的尽可能多的线程。尽管可以通过释放完成的线程(阈值是可配置的)来缓解这种情况,但这确