为什么python会以变量的方式运行?

时间:2018-01-10 16:48:30

标签: python python-3.x python-3.5 python-3.6

我一直试图理解为什么python会以这种方式运行,在下面的代码块中。我做了我的研究,但找不到一个好的答案所以我来到这里看看是否有人可以指出我正确的方向或提供一个很好的澄清。 我知道它与一些旧的ALGOL原理有关,但我不完全理解它。

var = 5

def func1():
    print(var)
func1()

def func2():
    var = 8
    print(var)
func2()

def func3():
    print(var)
    var = 8
func3()

此代码的输出如下:

5
8
UnboundLocalError:在赋值之前引用的局部变量'var'

我明白为什么我们得到输出'5'和'8'。但是使用'func3()',我期待输出'5'。看起来,解释器认为我想在函数中打印局部'var'而不是全局'var'。所以它抛出了这个错误。

或者如果在函数内部某处定义了一个变量,那么该函数将默认为局部变量,而不是具有相同名称的全局变量。

但是为什么python会这样表现呢?我不是在抱怨,我只是想了解一些事情......

如何在函数中使用预定义的全局变量,然后在同一函数内定义一个具有相同名称的局部变量,而不更改全局变量的值? (当然是在python中)

先感谢大家。你是个很棒的人! :)

Edit_1:感谢每一个人提供了很棒的答案。我完全理解在函数中使用预定义的全局变量是一个坏的和不切实际的想法,然后在同一个函数内定义一个具有相同名称的局部变量。我只是从理论的角度思考它,因为我在大学讲座中看到过它。 XD 我找不到一个用例,在这个用例中最好这样做!

Edit_2:我已经阅读了PEP8,我知道明确比隐含更好。 :) 这是真的。否则代码会混淆并导致错误。 这个问题只是我试图理解的一些无用且不切实际的大学理论。

Edit_3: 现在我完全理解为什么会发生这种情况以及这里发生了什么。感谢Randall Valencianoblog提供此链接,该链接解释得非常好。

该功能被解释为一个整体,而不是一行一行。因此,在解释函数时,任何已定义变量的变量声明都会移动到函数的顶部。因此,当我们打印'var'时,该函数正在使用本地声明的变量,该变量尚未分配任何值,然后解释器会抱怨它并抛出错误。

再次感谢大家! :) 你对我有很大的帮助!现在我终于明白了幕后发生了什么。

2 个答案:

答案 0 :(得分:11)

您的var被定义为全局变量。在每个函数中,当您只读取var您正在访问全局变量时,但是当函数中的某个地方有var的赋值时,python将函数中的每个 var视为局部变量。这就是为什么你的上一个函数失败了,因为在print(var)被分配之前调用了var = 8(本地变量函数)。

您可以在这些主题中阅读更多内容:
How bad is shadowing names defined in outer scopes?
Python nonlocal statement

最好的做法是明确您的代码,以便在您尝试引用本地,非本地或全局变量时不再混淆。

在这种情况下,假设您打算继续使用全局变量,请执行以下操作:

var = 5

def func1():
    print(var)
func1()

def func2():
    global var
    var = 8
    print(var)
func2()

def func3():
    global var
    print(var)
    var = 8  # technically this is not necessary any more var = 8 was already assigned when func2() is called
func3()

输出是:

5
8
8

修改:感谢juanpa.arrivillaga的评论 - 我错过了您原来的问题。

  

然后,如何在函数中使用预定义的全局变量   在同一个内部定义一个具有相同名称的局部变量   函数,而不改变全局变量的值? (in   当然是python)

简短的回答是 - 首先定义本地var,就像你在func2()中所做的一样,并且你很好。更长的答案是 - 你为什么要那样做?它会造成混乱,并且在跟踪不同范围内具有相同名称的变量时会变得很头疼。一个更好的方法是将您的本地变量命名为local_var或其他东西,使其明显不同并且可以轻松跟踪。

答案 1 :(得分:5)

以下是来自this answer

的Python范围解析规则

LEGB规则。

L,Local - 在函数(def或lambda)中以任何方式分配的名称,并且未在该函数中声明为全局。

E,Enclosing-function locals - 在内部到外部的任何和所有静态封闭函数(def或lambda)的本地范围内的名称。

G,Global(模块) - 在模块文件的顶层指定的名称,或者通过在文件中的def中执行全局语句。

B,内置(Python) - 在内置名称模块中预先指定的名称:open,range,SyntaxError,...

所以基本上在您的问题中,范围解析是“从内到外”,并且因为您没有使用global关键字,解释器不知道在本地函数范围之外查找该变量var。所有解释器都看到你在声明和定义变量之前使用变量,从而抛出错误。全局变量通常很危险,因此Python希望通过强制您明确它来确保您知道要使用全局变量。

有关global关键字

的说明,请参阅this other answer

希望它有所帮助。