usu*_* me 5 python global-variables
所以我可以从全局变量中读取
def f() :
print x
Run Code Online (Sandbox Code Playgroud)
我也可以分配它
def g()
global x
x = 3
Run Code Online (Sandbox Code Playgroud)
当人们说"全局变量不好"时,他们是否意味着阅读和分配都很糟糕,或者只是分配不好?(我的印象是阅读并不危险)
问题不在于"全局==坏",而在于"全局可变状态使得很难推断出程序流程"
为了说明,想象一下这个功能:
def frob():
if my_global:
wibble()
else:
wobble()
Run Code Online (Sandbox Code Playgroud)
也就是说,frob()s的行为取决于状态,无论是从身体的本体来看frob(),也不是从任何可能调用它的代码中都看不出来的.您必须尝试找出哪些更改my_global,以及何时更改发生与frob()调用何时相关.
编写小脚本时,这不是什么大问题,您可以看到并理解全局变量发生变化的所有位置,并且可能在它发生变化时以及在调用相关位时对其进行排序.在大型项目中,这需要更多的努力,以至于全球可变状态被广泛认为是一种反模式.
在所有的编程语言中,我们都有一个叫做作用域的概念。变量的作用域,简而言之,就是在源代码中可以访问该变量的区域。
想象一下,我们没有这个。您是否曾尝试在需要唯一用户名的数百万用户的网站或游戏上注册帐户?在找到一个有效的方法之前,您是否经历了其中的三四个?您是否最终得到了与您最初想要的不一样的东西,而是在其末尾添加了无用的信息 ( username_2014_1234)?
现在假设没有编程语言有范围。每次必须命名变量时,您都会经历这个过程!即使在你自己的程序中,你也不能做这样的事情:
x = 5;
function add_6_to_x(x) {
return x + 6;
}
Run Code Online (Sandbox Code Playgroud)
使用适当的作用域(在函数中为变量赋予它们自己的局部作用域),这是有效的,因为x在两个地方指代不同的东西。没有它,就会出现名称冲突,必须由编译器解决,或者更有可能是可怜的程序员,因为他不能只命名一个变量并与他的生活融洽相处。
一些编程语言已经超出了简单的范围并引入了命名空间。命名空间可以以两种方式之一(甚至两种方式都可以!)。他们允许的一件事是限定命名方案。限定名称通过给名称一个前缀来表示它们来自哪里来解决名称冲突。假设有一种编程语言(没有)具有两个println功能。第一个 inSystem.IO使您能够打印到终端 (stdout) 或文件,就像您所期望的那样。另一个 inSystem.Printers尝试连接到系统的默认打印机并在纸上物理打印出该行。所以如果我写:
println("The quick brown fox jumped over the lazy dog.");
Run Code Online (Sandbox Code Playgroud)
我是什么意思?它应该打印到屏幕上还是纸上?但是使用命名空间:
using System;
System.IO.println("The quick brown fox jumped over the lazy dog.");
Run Code Online (Sandbox Code Playgroud)
现在已经很清楚了。现在等等,你可能会说:这让我真正获得了什么?毕竟,我必须多打字。这里的好处是我们可以有两个完全不同的功能,由两个独立的包提供,具有相同的名称。想一想:你能想象如果每次你为一种特定的语言编写代码时,你都必须在网络上搜索是否有人之前定义过那个函数名吗?糟糕的!
命名空间做的另一件事是允许灵活性。如果我不想写System.IO.println怎么办?只要我只使用一个就可以了。大多数语言都是这样解决的:
using System.IO;
println("The quick brown fox jumped over the lazy dog.");
Run Code Online (Sandbox Code Playgroud)
我可以只在我的文件顶部放置一个命名空间限定,并且我可以无限定地调用println一整天。基本上,它将System.IO命名空间与我的文件 [1] 的命名空间合并。
两个都用怎么样?大多数语言都可以:
using System.IO.println;
using System.Printers.println as print_out;
Run Code Online (Sandbox Code Playgroud)
现在他们有了自己独立的(简短的、用户定义的)名称。伟大的!
显然,这给了开发人员很大的权力和灵活性,并解决了世界各地的开发人员可以并且很可能会为事物想出相同名称的问题,即使它们在上下文中完全不同。事实上,无论是作用域还是命名空间都是:标识符有效的上下文,以及它们所指的内容。
任何不在这种上下文中的东西都是全局的。有时全局变量看起来很有用,因为它们在普通变量不存在的地方可用。对于新程序员来说,这通常很诱人,因为如果您不知道如何访问它,您只需将其设为全局变量即可访问它。
但是全局名称通过忽略通常的作用域和命名空间规则(因为全局意味着它们存在于每个作用域和命名空间中)而违反了上述所有安排。如果每个人都简单地将所有变量设为全局变量,我们将立即回到 的可怕世界myVar_2014_1234,而且可能很多事情都会停止工作。
所以当人们说,“全球名称不好”,或者表现得好像你只是因为你使用了希特勒而复活了希特勒,并不是因为它们没有用。这是因为他们喜欢我们整齐包含的范围和命名空间的美好世界(毕竟,它们在每种现代编程语言中都是有原因的!),而您违反了该协议。这与人们不喜欢你在街上扔垃圾的原因是一样的:如果每个人都这样做,世界将是一个丑陋、凌乱、不适宜居住的地方。请不要滥用全局名称。:)
[1]:这与范围几乎相同,但我们通常不这么称呼它。