python关于函数作用域
本帖最后由 产品执行码暂缺 于 2020-8-3 16:08 编辑看视频课倒是理解了局部变量只可以访问,不能操作的意思。但是又有一些问题,请看下面三段代码:
第1段
def fun1():
x = 5
def fun2(x):
x -= 1
fun2(x)
print(x)
fun1()
结果是5 可以用局部变量不影响全局来解释,所以结果还是5
第2段
def fun1():
x = 5
def fun2():
x -= 1
fun2()
print(x)
fun1()
程序会报错 按照视频所讲内容,fun2()里面的局部变量x没被定义,所以不能对x操作-1,会报错。与第1段不同之处在于定义fun2函数时去掉了参数(x),为什么就不行了呢?
第3段
def fun1():
x = 5
def fun2():
return x - 1
print(fun2())
fun1()
结果是4 这就奇怪了,fun2()里面的return返回x - 1,这一步 x - 1 不属于'操作'么,这怎么前面有 return 就能运行了呢? 本帖最后由 sunrise085 于 2020-8-3 16:04 编辑
这不是闭包问题,是作用域问题
第三段中并没有对x进行修改操作。只有对x进行修改操作才会触发这个机制。
像 int 、 float 、 str 等类型是一类不可变类型,所谓不可变类型,就是定义即赋值,修改实际上是新的定义,这一类变量的定义和修改都是使用赋值运算符 '='。
像 list 、 set 、 dict 等类型是一类可变类型,所谓可变类型,就是定义之后,还可以对变量进行修改,修改前后,该变量的 id 不变,这一类变量定义使用赋值运算符,修改则需要下标(或键),还可以有插入、删除等操作。
对于不可变类型的变量,若是在函数内部进行修改的话,会有歧义,无法识别到底是修改同名的全局变量,还是定义一个同名的局部变量(因为修改和定义方式是一样的)。因此在函数内若使用不可变类型的全局变量时需要使用 global 进行明确指出。
对于可变类型,则不存在这种歧义,若是在函数内部修改一个与全局变量同名的变量,不会被认为是要创建一个同名的局部变量(因为修改和定义方式是不一样的),当在函数内没有定义一个与全局变量同名的局部变量,那么修改一个同名的变量时,能够明确就是修改全局变量。因此在函数内若使用一个可变类型的全局变量时不需要使用 global 明确指出。
看一下我这个帖子:Python细节之7、global与nonlocal的使用
第一个代码,你将 x 传入了 fun2 作用域中,所以此时 fun2 作用域是能直接找到具体的 x 参数,就触发屏蔽效果
但是你 fun2 函数已经重新找了个值来和 x 原先的赋值,所以在 x -= 1 即 x = x - 1 时候, x - 1 是找的到 x = 5 的
而你第二个代码没有将 x 传入,导致赋值直接触发屏蔽,在 fun2 命名空间找不到 x 的参数值,所以此时导致报错
第三段代码是直接返回 x - 1 的结果,而没对 x 直接赋值,所以不会触发屏蔽机制
第一段和第二段的差别白话点来说,就是第一个函数找到了一个与全局变量互通媒介,而第二段没有
根据你的第一个实例,这是作用域的问题
我给你一段代码:
def fun1():
x=5
def fun2():
print(x)
fun2()
print(x)
fun1()
它会打印两个5,那个x被定义在外面的那层函数fun1当中,但是可以被内层的fun2函数访问
第二个示例:
def fun1():
x=5
def fun2():
print(x)
x=4
fun2()
print(x)
fun1()
这段代码会报错,x原本属于fun1,虽然fun2可以访问读取x,但是不能修改
所以:
你的第一个示例不报错是因为fun2(x)
意思是fun2也有个和第一个fun1名字相同的变量x,但是他们是两个所属不同函数的变量,x-=1其实访问的是fun2的变量
你的第二个示例中,因为fun2()
所以fun2没有变量x,这个时候调用x-=1其实是调用fun1的x,根据刚刚我的两个示例已经证明,这是不可取的
你的第三个示例,因为return x-1,这一步只能算是对x的值进行读取并进行减一运算,没有对fun1的x进行修改,所以不报错
还有就是python对于缩进比较敏感,我刚刚将你的代码复制到我的编辑器当中总是报错,最终发现是缩进问题,我的编辑器自动将缩进换成4个空格,而你的是tab,因此报错
sunrise085 发表于 2020-8-3 16:02
这不是闭包问题,是作用域问题
第三段中并没有对x进行修改操作。只有对x进行修改操作才会触发这个机制。
...
谢谢 你的global 和 nonlocal 讲得很清楚 ,读过以后尝试了下,理解更清楚了 本帖最后由 产品执行码暂缺 于 2020-8-3 17:23 编辑
狼式编程 发表于 2020-8-3 16:24
根据你的第一个实例,这是作用域的问题
我给你一段代码:
感谢 return这里你说的很清楚 Twilight6 发表于 2020-8-3 16:22
第一个代码,你将 x 传入了 fun2 作用域中,所以此时 fun2 作用域是能直接找到具体的 x 参数,就触发屏 ...
3q
第一段的fun2是把fun1中传过来的x = 5接收了,变成自己fun2的参数,再去执行下面的 x -= 1,触发屏蔽,对局部变量x操作、修改,没有问题
第二段的fun2什么都没有,直接碰到x -= 1,调用了fun1的x=5,赋值修改就不行了
页:
[1]