wbzxz 发表于 2023-6-25 21:48:04

只是多了一个print语句,咋就报错了呢?

代码1:
>>> x = 880
>>> def myfunc():
        x = 520
        print(x)

       
>>> myfunc()
520

代码2:
>>> def myfunc():
        print(x)
        x = 520
        print(x)

       
>>> myfunc()
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
    myfunc()
File "<pyshell#12>", line 2, in myfunc
    print(x)
UnboundLocalError: local variable 'x' referenced before assignment

代码2 相比 代码1 ,只是多了一个print(x)语句, 咋就报错了呢? 感觉是变量作用域的问题,但是不知道错在哪里了, 请老师指点。

isdkz 发表于 2023-6-25 22:14:40

这个错误确实是因为变量作用域的问题。

在 Python 中,当你在函数内部对一个变量进行赋值操作的时候,这个变量会被 Python 解释器认为是一个局部变量,除非你明确地声明它是全局的。这就是为什么在你的第二个例子中,当你试图在赋值之前打印变量 x 的时候,Python 会抛出一个错误。因为在这个时间点,x 还没有在局部作用域内定义。

你的代码1中,函数 myfunc() 内部有个局部变量x,与全局变量x是完全不同的两个变量。所以在函数内部先给x赋值520,然后打印x,结果自然是520。

但在代码2中,函数内部的print(x)在x=520之前,也就是在局部变量x被定义之前就要求打印x,所以就会报错。

如果你想在函数内部使用全局变量x,你需要使用 global 关键字,如下所示:

x = 880

def myfunc():
    global x
    print(x)
    x = 520
    print(x)

myfunc()

在这个例子中, global x 告诉 Python:在这个函数内,我想要使用全局的 x,而不是创建一个新的局部变量 x。所以函数首先会打印出全局变量x的值880,然后将全局变量x赋值为520,并打印出520。

wbzxz 发表于 2023-6-26 06:07:37

isdkz 发表于 2023-6-25 22:14
这个错误确实是因为变量作用域的问题。

在 Python 中,当你在函数内部对一个变量进行赋值操作的时候,这 ...

谢谢您,但是我还没有理解透彻。

您的意思是不是说,出错的原因,是局部变量x没有定义就要求打印,所以才报错。但是为什么下面的代码不会出错呢?(代码中变量x没有被定义,也是直接打印x)

>>> x = 880
>>> def myfunc():
        print(x)

       
>>> myfunc()
880

谢谢您,请多指点。

isdkz 发表于 2023-6-26 08:49:09

wbzxz 发表于 2023-6-26 06:07
谢谢您,但是我还没有理解透彻。

您的意思是不是说,出错的原因,是局部变量x没有定义就要求打印,所 ...

当你在一个函数内部引用一个变量,Python 会按照以下顺序来查找这个变量:

1. 首先,它会在当前函数的局部作用域内查找。
2. 如果在局部作用域内找不到,它会在任何封闭的作用域内查找,从内到外。封闭的作用域可能是在一个外部函数或者是一个类定义的范围内。
3. 如果在封闭的作用域内也找不到,Python 会在全局作用域内查找。
4. 最后,如果在全局作用域内也找不到,Python 会在内建的作用域内查找。

在你给出的新代码示例中,你只是引用了变量x而没有尝试在myfunc的局部作用域内对其进行赋值。因此,Python 会按照上述规则查找变量x ,它先在局部作用域查找,找不到后在全局作用域找到了x ,因此print(x)可以正确打印出x的值。

然而,在你的第二个代码示例中,你尝试在myfunc的局部作用域内对x进行赋值。这导致 Python 将x视为一个局部变量,而不再去全局作用域查找。然后,当你在赋值之前尝试打印x时,由于x在此时还未被定义,因此 Python 抛出了UnboundLocalError错误。

我希望这个解释可以帮助你更好地理解 Python 的作用域规则!

wbzxz 发表于 2023-6-26 14:16:38

isdkz 发表于 2023-6-26 08:49
当你在一个函数内部引用一个变量,Python 会按照以下顺序来查找这个变量:

1. 首先,它会在当前函数 ...

非常感谢您的指点。
您看我能不能这样理解,其实这个问题的关键时由于我使用了赋值语句,所以造成python以为 myfunc 函数中x变量一定是局部变量,不会按照LEGB规则进行查找啦。而在x变量赋值之前,使用了print(x)语句,python就认为没有复制就引用啦,所以出现错误啦。

而在代码一中,虽然也使用了赋值语句,python也认为函数内部的x变量是局部变量。由于没有在赋值前访问x变量,而是先给变量赋了值,这样就不会出错啦。

您看我这样理解对不,但我的描述肯定不准确,除了赋值语句会引起这个问题, 还有什么语句会引起类似错误呢?

isdkz 发表于 2023-6-26 14:19:25

wbzxz 发表于 2023-6-26 14:16
非常感谢您的指点。
您看我能不能这样理解,其实这个问题的关键时由于我使用了赋值语句,所以造成python ...

你的理解是正确的!在函数中,只要我们对一个变量进行赋值操作,无论这个赋值操作在哪里,Python 都会认为这个变量是局部的,除非你明确地用global或nonlocal声明它。如果在赋值之前就试图访问这个变量,就会遇到UnboundLocalError错误。

这是因为在编译函数的时候,Python 会决定变量是全局的还是局部的。在函数体中,任何在赋值语句( = )左侧的变量,都会被认为是局部变量,除非明确地声明为全局变量或非局部变量。

对于你的第二个问题,其实不仅仅是赋值语句会引起这个问题,任何试图修改一个变量的操作都会让 Python 将这个变量视为局部的,如果没有明确声明它是全局的。例如:

x = 880

def myfunc():
    x += 1    # This is effectively an assignment operation
    print(x)

myfunc()


这段代码也会抛出UnboundLocalError错误,因为x += 1本质上是x = x + 1 ,是一种赋值操作。Python 认为x是局部的,但是在赋值之前已经引用了x ,导致错误。

所以总的来说,只要在函数内部修改变量的值,如果不想让 Python 将其视为局部变量,就需要使用global或nonlocal关键字明确声明。
页: [1]
查看完整版本: 只是多了一个print语句,咋就报错了呢?