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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19158339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 13:01:19  来源:igfitidea点击:

Why are global variables evil?

pythonglobal-variablesside-effects

提问by LarsVegas

I was trying to find a good source that explains why the use of globalis considered to be bad practice in python (and in programming in general). Can somebody point me to one or explain here?

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

采纳答案by Erik Kaplun

This has nothing to do with Python; global variables are bad in any programming language.

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

However, global constantsare not conceptually the same as global variables; global constants are perfectly harmless. In Python the distinction between the two is purely by convention: CONSTANTS_ARE_CAPITALIZEDand globals_are_not.

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

The reason global variables are bad is that they enable functions to have hidden (non-obvious, surprising, hard to detect, hard to diagnose) side effects, leading to an increase in complexity, potentially leading to Spaghetti code.

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

However, sane use of global state is acceptable (as is local state and mutability) even in functional programming, either for algorithm optimization, reduced complexity, caching and memoization, or the practicality of porting structures originating in a predominantly imperative codebase.

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

All in all, your question can be answered in many ways, so your best bet is to just google "why are global variables bad". Some examples:

总而言之,您的问题可以通过多种方式得到解答,因此您最好的办法就是在 google 上搜索“为什么全局变量不好”。一些例子:

If you want to go deeper and find out why side effects are all about, and many other enlightening things, you should learn Functional Programming:

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

回答by georg

Yes, in theory, globals (and "state" in general) are evil. In practice, if you look into your python's packages directory you'll find that most modules there start with a bunch of global declarations. Obviously, people have no problem with them.

是的,理论上,全局变量(以及一般的“状态”)是邪恶的。实际上,如果您查看 Python 的包目录,您会发现那里的大多数模块都以一堆全局声明开头。显然,人们对他们没有任何问题。

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.

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

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:

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

cache = {}

def foo(args):
    global cache

    cache[args] = ...

This makes globals' manipulations easier to track down.

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

回答by Rafael

A personal opinion on the topic is that having global variables being used in a function logic means that some other code can alter the logic and the expected output of that function which will make debugging very hard (especially in big projects) and will make testing harder as well.

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

Furthermore, if you consider other people reading your code (open-source community, colleagues etc) they will have a hard time trying to understand where the global variable is being set, where has been changed and what to expect from this global variable as opposed to an isolated function that its functionality can be determined by reading the function definition itself.

此外,如果您认为其他人正在阅读您的代码(开源社区、同事等),他们将很难理解全局变量的设置位置、更改的位置以及该全局变量的期望值,而不是一个独立的函数,它的功能可以通过阅读函数定义本身来确定。

(Probably) Violating Pure Function definition

(可能)违反纯函数定义

I believe that a clean and (nearly) bug-free code should have functions that are as pure as possible (see pure functions). A pure function is the one that has the following conditions:

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

  1. The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices (usually—see below).
  2. Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
  1. 给定相同的参数值,该函数始终计算相同的结果值。函数结果值不能依赖于在程序执行过程中或程序的不同执行之间可能改变的任何隐藏信息或状态,也不能依赖于来自 I/O 设备的任何外部输入(通常 - 见下文)。
  2. 结果的评估不会导致任何语义上可观察的副作用或输出,例如可变对象的突变或输出到 I/O 设备。

Having global variables is violating at least one of the above if not both as an external code can probably cause unexpected results.

拥有全局变量至少违反了上述之一,因为外部代码可能会导致意外结果。

Another clear definition of pure functions: "Pure function is a function that takes all of its inputs as explicit argumentsand produces all of its outputs as explicit results." [1]. Having global variables violates the idea of pure functions since an input and maybe one of the outputs (the global variable) is not explicitly being given or returned.

纯函数的另一个明确定义:“纯函数是一种将其所有输入作为显式参数并将其所有输出作为显式结果产生的函数。” [1]. 拥有全局变量违反了纯函数的思想,因为输入和输出之一(全局变量)没有明确给出或返回。

(Probably) Violating Unit testing F.I.R.S.T principle

(可能)违反单元测试第一原则

Further on that, if you consider unit-testing and the F.I.R.S.T principle (Fast tests, Independent tests, Repeatable, Self-Validating and Timely) will probably violate the Independent tests principle (which means that tests don't depend on each other).

另外对,如果你考虑的单元测试和第一原理(˚FAST测试,ndependent测试,[Repeatable,Ş精灵验证和牛逼imely)可能会违反独立的测试原理(这意味着测试不依赖彼此)。

Having a global variable (not always) but in most of the cases (at least of what I have seen so far) is to prepare and pass results to other functions. This violates this principle as well. If the global variable has been used in that way (i.e the global variable used in function X has to be set in a function Y first) it means that to unit test function X you have to run test/run function Y first.

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

Globals as constants

作为常量的全局变量

On the other hand and as other people have already mentioned, if the global variable is used as a "constant" variable can be slightly better since the language does not support constants. However, I always prefer working with classes and having the "constants" as a class member and not use a global variable at all. If you have a code that two different classes require to share a global variable then you probably need to refactor your solution and make your classes independent.

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

I don't believe that globals shouldn't be used. But if they are used the authors should consider some principles (the ones mentioned above perhaps and other software engineering principles and good practices) for a cleaner and nearly bug-free code.

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

回答by Horst Schlawutzke

They are essential, the screen being a good example. However, in a multithreaded environment or with many developers involved, in practice often the question arises: who did (erraneously) set or clear it? Depending on the architecture, analysis can be costly and be required often. While reading the global var can be ok, writing to it must be controlled, for example by a single thread or threadsafe class. Hence, global vars arise the fear of high development costs possible by the consequences for which themselves are considered evil. Therefore in general, it's good practice to keep the number of global vars low.

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