“全局变量是坏的”是什么意思?

时间:2014-04-01 21:08:12

标签: python global-variables

所以我可以从全局变量中读取

def f() :
  print x

我也可以分配它

def g()
  global x
  x = 3

当人们说“全局变量不好”时,他们是否意味着阅读和分配都不好,或者只是分配不好? (我的印象是阅读并不危险)

3 个答案:

答案 0 :(得分:9)

问题不在于“全局==坏”,而在于“全局可变状态使得很难推断出程序流程”

为了说明,想象一下这个功能:

def frob():
    if my_global:
        wibble()
    else:
        wobble()

也就是说,frob()的行为取决于frob()的主体,以及可能调用它的任何代码的性质不明显的状态。您必须尝试找出哪些更改my_global,以及这些更改何时发生关系到何时调用frob()

编写小脚本时,这不是什么大问题,你可以看到并理解全局变量发生变化的所有地方,并且当它发生变化和调用相关位时,可能会在脑中排序。在大型项目中,这需要更多的努力,以至于全球可变状态被广泛认为是一种反模式。

答案 1 :(得分:4)

在所有编程语言中,我们都有这个概念,称为范围。简单地说,变量的范围是源代码中可以访问该变量的区域。

想象一下,我们没有这个。您是否曾尝试在数百万需要独特用户名的用户的网站或游戏上注册帐户?你找到一个有效的之前,你经历过三到四个吗?你最终得到的东西与你原来想要的东西没什么相似,而是在它的末尾添加了无用的信息(username_2014_1234)?

现在假设没有编程语言有范围。每次你必须命名一个变量时,你会经历这个!即使在你自己的程序中,你也做不到这样的事情:

x = 5;
function add_6_to_x(x) {
    return x + 6;
}

使用适当的范围(在函数中为变量提供自己的 local 范围),这是有效的,因为x指的是两个地方都有不同的东西。如果没有它,就会有一个名称冲突,必须由编译器解决,或者更可能的是,那些不能只为变量命名并与他的生活相处的程序员。

有些编程语言超出了简单的范围,并引入了命名空间。命名空间可以采用两种方式之一(甚至两种方式!)。他们允许的一件事是合格的命名方案。限定名称通过为名称指定前缀来表示名称冲突,以表示它们来自何处。假设有一种编程语言(那里没有)有两个println函数。第一个,在System.IO中,使您能够打印到终端(stdout)或文件,就像您期望的那样。另一个,在System.Printers中,尝试连接到系统的默认打印机,并在纸上物理打印出该行。所以,如果我写:

println("The quick brown fox jumped over the lazy dog.");

我的意思是什么?它应该打印到屏幕还是纸张上?但是使用命名空间:

using System;
System.IO.println("The quick brown fox jumped over the lazy dog.");

现在非常清楚。现在等一下,你可能会说:这真的让我获得了什么?毕竟,我必须进行更多输入。这里的好处是我们可以有两个完全不同的功能,由两个独立的包提供,具有相同的名称。想一想:你能想象如果每次为特定语言编写代码,你都必须在网上搜索,看看是否有人之前已经定义了这个功能名称?可怕!

名称空间做的另一件事是允许灵活性。如果我不想写System.IO.println怎么办?只要我只使用一个就好了。大多数语言解决这个问题:

using System.IO;
println("The quick brown fox jumped over the lazy dog.");

我可以在我的文件顶部放置一个名称空间限定条件,我可以在没有资格的情况下整天致电println。基本上,它将System.IO命名空间与我的文件[1]的命名空间合并。

如何使用两者?大多数语言都可以:

using System.IO.println;
using System.Printers.println as print_out;

现在他们有自己独立的(用户自定义的)短名称。太好了!

显然,这为开发人员提供了很大的功能和灵活性,并且解决了全世界的开发人员可能,并且很可能会为事物提出相同名称的问题,即使他们是这样的。在语境上完全不同的东西。实际上,所有范围或命名空间都是: context ,标识符有效,以及它们引用的内容。

任何不在这种背景下的是全球。有时全局变量似乎很有用,因为它们可以在普通变量不可用的地方使用。对于新的程序员来说,这通常是诱人的,因为如果你不知道怎么做到这一点,你可以简单地通过将变量设为全局来访问变量。

但是全局名称违反了所有上述安排,忽略了范围和命名空间的通常规则(因为全局意味着它们存在于每个范围和命名空间中)。如果每个人都简单地将所有变量全局化,我们就会回到myVar_2014_1234这个可怕的世界,可能很多东西都会停止运作。

因此,当人们说,"全球名称不好时,或者就像你刚刚复活了希特勒一样,因为你使用了一个,它的不是,因为他们'没用。这是因为他们喜欢我们整洁的包含范围和命名空间的美好世界(毕竟,他们是出于某种原因而出现在每种现代编程语言中!),并且您违反了该协议。当你在街上扔垃圾时,人们不喜欢它的原因是相同的:如果每个人都这样做,世界将是一个丑陋,凌乱,无法放置的地方。请不要滥用全球名称。 :)

[1]:这与范围几乎相同,但我们通常不会这样称呼它。

答案 2 :(得分:2)

全局变量可以从几乎所有地方进行更改和访问。这可能包括碰撞命名空间和分配,你不想拥有它们。

举个例子:

def someFunction(): 
    global myVar 
    myVar = "fuuu" 
    print myVar

myVar = "baa" 
f() 
print myVar 

会以类似的方式结束。

fuuu
fuuu 

而你可能期望

fuuu 
baa

所以我说两种变体都有点危险。