Python中为什么函数内可以直接修改外部类实例的属性?

例如:
class C(object):
def init(self):
self.a = 0

def f ©:
c.a += 1
c.b = 2

c0 = C()
print(c0.a)
f(c0)
print(c0.a, c0.b)

输出:
0
1 2

这样感觉很像全局变量。这应该怎么理解?请问有没有相关的文档可以阅读呢?
Python中为什么函数内可以直接修改外部类实例的属性?

4 回复

实例化时候修改类中的成员变量~?


这个问题涉及到Python的作用域和命名空间规则,核心在于属性访问变量赋值的区别。

简单来说,在函数内部,obj.attr = value 这种操作不是在修改一个“外部变量”,而是在对一个已存在的对象 obj 进行属性操作。Python查找 obj 这个名称时,遵循 LEGB 规则,在你的例子中,它很可能在外部作用域找到了这个对象引用。找到之后,obj.attr = value 就变成了“请求对象 obj 设置其属性 attr”,这个操作是作用在对象本身上的,与函数的作用域无关。

这里的关键是区分:

  • 修改对象属性 (obj.attr = value): 这是允许的,因为你只是使用了对象引用。
  • 重新绑定变量名 (obj = new_value): 这会在函数的局部作用域创建一个新的局部变量 obj,而不会影响外部作用域的同名变量。

看个对比代码就清楚了:

class MyClass:
    def __init__(self):
        self.value = 10

def modify_attr(obj):
    """这个函数可以成功修改外部对象的属性"""
    obj.value = 20  # 通过传入的对象引用,修改其属性

def rebind_variable(obj):
    """这个函数无法修改外部变量本身"""
    obj = MyClass()  # 这只会在函数内部创建一个新的局部变量 `obj`
    obj.value = 30

# 测试
my_obj = MyClass()
print(f"初始值: {my_obj.value}")  # 输出: 初始值: 10

modify_attr(my_obj)
print(f"调用 modify_attr 后: {my_obj.value}")  # 输出: 调用 modify_attr 后: 20

rebind_variable(my_obj)
print(f"调用 rebind_variable 后: {my_obj.value}")  # 输出: 调用 rebind_variable 后: 20 (值未变)

总结一下: 你能修改属性是因为你操作的是对象本身,而不是变量名绑定的关系。

c0 = C() 实例化了 C 之后 C 原本有 c0 就是一个 class 类,里面有成员变量 c0.a
或者说每一个实例化的 C 类里面都默认有一个成员变量 a=0
print(c0.a) 所以输出了 0

f(c0)把 c0 里面默认的 a 变量自增了 1 所以 c0.a 在 c.a += 1 是 1(原本默认是 0)
又新增了一个 b=2 所以最后输出的时候是 1 2

不知道我这样理解的对不对,等大佬来解答一下

Python 和 Java 等面向对象的编程语言在函数调用的时候都是传递引用的

回到顶部