鱼C论坛

 找回密码
 立即注册
查看: 1376|回复: 6

[已解决]python关于函数作用域

[复制链接]
发表于 2020-8-3 15:59:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 产品执行码暂缺 于 2020-8-3 16:08 编辑

看视频课倒是理解了局部变量只可以访问,不能操作的意思。但是又有一些问题,请看下面三段代码:
第1段
  1. def fun1():
  2.     x = 5

  3.     def fun2(x):
  4.         x -= 1

  5.     fun2(x)

  6.     print(x)

  7. fun1()
复制代码

结果是5        可以用局部变量不影响全局来解释,所以结果还是5

第2段
  1. def fun1():
  2.     x = 5

  3.     def fun2():
  4.         x -= 1

  5.     fun2()

  6.     print(x)

  7. fun1()
复制代码

程序会报错        按照视频所讲内容,fun2()里面的局部变量x没被定义,所以不能对x操作-1,会报错。与第1段不同之处在于定义fun2函数时去掉了参数(x),为什么就不行了呢?

第3段
  1. def fun1():
  2.     x = 5

  3.     def fun2():
  4.         return x - 1

  5.     print(fun2())

  6. fun1()
复制代码

结果是4                这就奇怪了,fun2()里面的return返回x - 1,这一步 x - 1 不属于'操作'么,这怎么前面有 return 就能运行了呢?
最佳答案
2020-8-3 16:02:20
本帖最后由 sunrise085 于 2020-8-3 16:04 编辑

这不是闭包问题,是作用域问题
第三段中并没有对x进行修改操作。只有对x进行修改操作才会触发这个机制。

像 int 、 float 、 str 等类型是一类不可变类型,所谓不可变类型,就是定义即赋值,修改实际上是新的定义,这一类变量的定义和修改都是使用赋值运算符 '='。
像 list 、 set 、 dict 等类型是一类可变类型,所谓可变类型,就是定义之后,还可以对变量进行修改,修改前后,该变量的 id 不变,这一类变量定义使用赋值运算符,修改则需要下标(或键),还可以有插入、删除等操作。
对于不可变类型的变量,若是在函数内部进行修改的话,会有歧义,无法识别到底是修改同名的全局变量,还是定义一个同名的局部变量(因为修改和定义方式是一样的)。因此在函数内若使用不可变类型的全局变量时需要使用 global 进行明确指出。
对于可变类型,则不存在这种歧义,若是在函数内部修改一个与全局变量同名的变量,不会被认为是要创建一个同名的局部变量(因为修改和定义方式是不一样的),当在函数内没有定义一个与全局变量同名的局部变量,那么修改一个同名的变量时,能够明确就是修改全局变量。因此在函数内若使用一个可变类型的全局变量时不需要使用 global 明确指出。


看一下我这个帖子:Python细节之7、global与nonlocal的使用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-8-3 16:02:20 | 显示全部楼层    本楼为最佳答案   
本帖最后由 sunrise085 于 2020-8-3 16:04 编辑

这不是闭包问题,是作用域问题
第三段中并没有对x进行修改操作。只有对x进行修改操作才会触发这个机制。

像 int 、 float 、 str 等类型是一类不可变类型,所谓不可变类型,就是定义即赋值,修改实际上是新的定义,这一类变量的定义和修改都是使用赋值运算符 '='。
像 list 、 set 、 dict 等类型是一类可变类型,所谓可变类型,就是定义之后,还可以对变量进行修改,修改前后,该变量的 id 不变,这一类变量定义使用赋值运算符,修改则需要下标(或键),还可以有插入、删除等操作。
对于不可变类型的变量,若是在函数内部进行修改的话,会有歧义,无法识别到底是修改同名的全局变量,还是定义一个同名的局部变量(因为修改和定义方式是一样的)。因此在函数内若使用不可变类型的全局变量时需要使用 global 进行明确指出。
对于可变类型,则不存在这种歧义,若是在函数内部修改一个与全局变量同名的变量,不会被认为是要创建一个同名的局部变量(因为修改和定义方式是不一样的),当在函数内没有定义一个与全局变量同名的局部变量,那么修改一个同名的变量时,能够明确就是修改全局变量。因此在函数内若使用一个可变类型的全局变量时不需要使用 global 明确指出。


看一下我这个帖子:Python细节之7、global与nonlocal的使用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-3 16:22:47 | 显示全部楼层


第一个代码,你将 x 传入了 fun2 作用域中,所以此时 fun2 作用域是能直接找到具体的 x 参数,就触发屏蔽效果

但是你 fun2 函数已经重新找了个值来和 x 原先的赋值,所以在 x -= 1 即 x = x - 1 时候, x - 1 是找的到 x = 5 的


而你第二个代码没有将 x 传入,导致赋值直接触发屏蔽,在 fun2 命名空间找不到 x 的参数值,所以此时导致报错


第三段代码是直接返回 x - 1 的结果,而没对 x 直接赋值,所以不会触发屏蔽机制


第一段和第二段的差别白话点来说,就是第一个函数找到了一个与全局变量互通媒介,而第二段没有
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2020-8-3 16:24:07 | 显示全部楼层
根据你的第一个实例,这是作用域的问题
我给你一段代码:
  1. def fun1():
  2.         x=5
  3.         def fun2():
  4.                 print(x)
  5.         fun2()
  6.         print(x)
  7. fun1()
复制代码

它会打印两个5,那个x被定义在外面的那层函数fun1当中,但是可以被内层的fun2函数访问
第二个示例:
  1. def fun1():
  2.         x=5
  3.         def fun2():
  4.                 print(x)
  5.                 x=4
  6.         fun2()
  7.         print(x)
  8. 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,因此报错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-3 16:51:07 | 显示全部楼层
sunrise085 发表于 2020-8-3 16:02
这不是闭包问题,是作用域问题
第三段中并没有对x进行修改操作。只有对x进行修改操作才会触发这个机制。
...

谢谢 你的global 和 nonlocal 讲得很清楚 ,读过以后尝试了下,理解更清楚了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-3 16:55:47 | 显示全部楼层
本帖最后由 产品执行码暂缺 于 2020-8-3 17:23 编辑
狼式编程 发表于 2020-8-3 16:24
根据你的第一个实例,这是作用域的问题
我给你一段代码:


感谢 return这里你说的很清楚
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-3 17:10:39 | 显示全部楼层
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,赋值修改就不行了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-25 21:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表