为何replaceNode1可正常运行而replaceNode2不行?Python变量赋值疑问
为什么replaceNode1函数能正常运行,replaceNode2却不行?
先看你给出的代码片段:
class Node: def __init__(self, val): self.val = val self.left = None self.right = None def replaceNode1(): node = [None] def doit(val, node): node[0] = Node(val) doit(20, node) return node[0].val # 返回20 def replaceNode2(): node = None def doit(val, node): node = Node(val) doit(20, node) return node.val # 报错:'NoneType' has no attribute 'val'
核心原因在于Python的参数传递规则,以及可变对象和不可变对象的区别——你提到None是可变的?不对哦,None其实是不可变对象,而且这里的关键不是对象本身的可变性,而是函数内部对参数的操作方式。
我给你拆解一下两个函数的运行逻辑:
先看replaceNode1的运行过程
- 外层函数里
node = [None],这里的node是一个列表(可变对象),它就像一个装着None的盒子,变量node只是贴在这个盒子上的标签。 - 调用
doit(20, node)时,把这个盒子的标签复制了一份传给doit里的参数node——现在内外两个node标签都贴在同一个盒子上。 doit里执行node[0] = Node(val),这是修改盒子内部的内容:把盒子里原来的None换成了新的Node实例。- 回到外层函数,原来的
node标签还是贴在那个盒子上,自然能拿到修改后的内容,所以返回20没问题。
再看replaceNode2的问题所在
- 外层函数里
node = None,这里的node标签贴在了None这个不可变对象上(你可以把None理解成一个不能被修改的空盒子)。 - 调用
doit(20, node)时,同样复制了一份标签传给doit的参数node——现在内外两个node标签都贴在None这个空盒子上。 doit里执行node = Node(val),这不是修改原来的空盒子,而是把函数内部的node标签撕下来,重新贴到一个新的Node实例盒子上。- 外层函数的
node标签根本没动,还是贴在原来的None空盒子上,所以返回node.val时,自然会报错说NoneType没有val属性。
简单总结一下:
- 当你传递可变对象(比如列表、字典、自定义类实例)时,函数内部修改对象的内部状态,外部能看到变化;
- 当你传递不可变对象(比如None、整数、字符串)时,函数内部对参数的赋值操作,只会创建局部变量,不会影响外部的变量。
内容的提问来源于stack exchange,提问作者Michael Cheng
相关产品推荐
相关产品推荐

