鱼C论坛

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

[已解决]为什么python无参函数可以调用作用域外的对象

[复制链接]
发表于 2023-11-4 22:15:37 | 显示全部楼层 |阅读模式

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

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

x
class A:
    def __init__(self):
        self.a = 100

a = A()
def add():
    a.a += 20
add()
print(a.a)
## 输出结果:120
想问一下为什么add()可以调用作用域外的a.a
a.a并没有传参进去,也没有用关键字global
最佳答案
2023-11-5 23:12:23
我去运行了一下,第一个的报错是:
UnboundLocalError: local variable 'b' referenced before assignment
意思是在赋值之前引用了局部变量“b”。我就记起来这个是要用global的,b本来是全局变量,在函数add()内部,当你尝试修改b的值时,Python会将其视为新的局部变量,并且你不能直接修改全局变量的值。
总的就是,全局变量和实例对象的作用范围这种,可以说是规则吧是不同的,对于全局变量,你要用global来修改其值,而对于实例对象的属性,你可以直接通过实例对象来访问和修改。这种东西有时候没有个为什么,因为像是个规则一样的,自己记住就好,就是这种区别,但是我讲一下自己的理解吧(不一定对):
   变量的作用域是由其定义的位置决定的。全局变量是在函数外部定义的,可以在整个程序中访问。而局部变量是在函数内部定义的,只能在函数内部访问。在函数内部修改一个全局变量时,Python会将其当作一个新的局部变量处理,而不可以直接修改全局变量的值。我觉得这种设计像在大型程序中,都说全局变量的使用应该尽量避免嘛。通过将变量限定在函数内部或类的实例中,可以减少变量之间的相互影响,提高代码的模块化和可重用性。然后说类,类和对象嘛,对象就是可以有自己的属性,有自己的一种特定的属性方法一样的,设计这样的一种访问调用规则可以用起来更加方便灵活


个人的解答和看法,如有错误还请包涵

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-11-4 22:16:38 | 显示全部楼层
在Python中,函数可以访问作用域外的对象是因为Python解释器在查找变量时采用了一定的规则。这个规则被称为"LEGB"规则,即Local、Enclosing、Global和Built-in。

当函数内部引用一个变量时,Python解释器会按照以下顺序查找该变量:
1. Local(局部):首先在函数内部查找是否存在该变量。
2. Enclosing(封闭的父级函数):如果在函数内部没有找到该变量,就会继续查找外层函数是否定义了这个变量。
3. Global(全局):如果在封闭的父级函数中也没有找到该变量,就会在全局作用域中查找是否存在该变量。
4. Built-in(内建):如果都没有找到,最后会在Python的内建命名空间中查找。

在你提供的代码中,函数add()内部引用了变量a.a,而在该函数的封闭环境中并没有定义这个变量。接着,Python解释器根据LEGB规则去查找这个变量。由于在Global作用域中找到了a,所以可以进行访问和修改。

需要注意的是,如果要在函数中修改全局变量的值,必须使用global关键字来声明。但是在你提供的代码中,并没有修改全局变量a,而是修改了a.a。因此,不需要使用global关键字。

希望这个解释对你有帮助!如果还有其他问题,请随时提问。

球一个最佳答案谢谢啦!这对我非常重要!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-11-4 22:16:53 | 显示全部楼层
在Python中,函数可以访问并修改作用域外的对象,无论是全局作用域还是嵌套作用域。这是因为在Python中,函数在访问变量时会按照一定的顺序查找变量的定义。

在你的代码中,函数 add() 可以访问作用域外的 a.a ,因为在函数内部没有定义同名的局部变量 a.a 。当函数 add() 试图访问变量 a.a 时,它会按照以下顺序查找变量的定义:

1. 首先,它会查找函数内部的局部作用域,也就是 add() 函数内部是否有定义同名的局部变量 a.a 。
2. 如果在局部作用域中找不到对应的变量,它会继续在嵌套的作用域中查找。在这种情况下,嵌套作用域是全局作用域。
3. 如果在嵌套作用域中找到了对应的变量,函数就可以访问并修改它。

所以,在你的代码中,函数 add() 可以访问并修改作用域外的 a.a ,因为它在嵌套作用域中找到了对应的变量。这种行为不需要使用 global 关键字,因为没有需要在函数内部重新定义的同名局部变量。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-11-4 22:18:21 | 显示全部楼层
你这个a不是全局变量嘛
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-11-4 22:19:40 | 显示全部楼层
yinda_peng 发表于 2023-11-4 22:18
你这个a不是全局变量嘛
class A:
    def __init__(self):
        self.a = 100
b = 10
a = A()
def add():
    b += 10
    a.a += 20
add()
print(a.a)
print(b)
你看看这段代码全局变量b就会报错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-11-4 22:25:35 | 显示全部楼层
b = 10
def add():
    b += 10
add()
print(b)
兄弟们咋回事啊,变量就会报错,实例对象就不会报错,
class A:
    def __init__(self):
        self.a = 100
a = A()
def adda():
    a.a +=10
adda()
print(a.a)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-11-5 23:12:23 | 显示全部楼层    本楼为最佳答案   
我去运行了一下,第一个的报错是:
UnboundLocalError: local variable 'b' referenced before assignment
意思是在赋值之前引用了局部变量“b”。我就记起来这个是要用global的,b本来是全局变量,在函数add()内部,当你尝试修改b的值时,Python会将其视为新的局部变量,并且你不能直接修改全局变量的值。
总的就是,全局变量和实例对象的作用范围这种,可以说是规则吧是不同的,对于全局变量,你要用global来修改其值,而对于实例对象的属性,你可以直接通过实例对象来访问和修改。这种东西有时候没有个为什么,因为像是个规则一样的,自己记住就好,就是这种区别,但是我讲一下自己的理解吧(不一定对):
   变量的作用域是由其定义的位置决定的。全局变量是在函数外部定义的,可以在整个程序中访问。而局部变量是在函数内部定义的,只能在函数内部访问。在函数内部修改一个全局变量时,Python会将其当作一个新的局部变量处理,而不可以直接修改全局变量的值。我觉得这种设计像在大型程序中,都说全局变量的使用应该尽量避免嘛。通过将变量限定在函数内部或类的实例中,可以减少变量之间的相互影响,提高代码的模块化和可重用性。然后说类,类和对象嘛,对象就是可以有自己的属性,有自己的一种特定的属性方法一样的,设计这样的一种访问调用规则可以用起来更加方便灵活


个人的解答和看法,如有错误还请包涵
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-21 15:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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