Python调用类方法意外修改无关实例,or []语法为何能解决该问题
问题原理解答
1. 第一段代码修改node_j属性的核心原因
你遇到的是Python中可变默认参数的经典坑:
- Python的函数默认参数是在函数定义阶段就完成初始化的,而非每次调用函数时重新生成
- 你的
__init__方法里默认参数itslist=[]是可变的列表类型,所有创建实例时没有主动传入itslist参数的对象,共享内存中同一个列表实例 - 你创建
node_i和node_j时都没有传itslist,所以node_i.itslist和node_j.itslist指向完全相同的列表对象 - 调用
node_i.extend_list(node_j)时,本质是往这个公共列表里添加了node_j对象,自然访问node_j.itslist的时候也能读到刚添加的元素,打印就会出现J->J的异常结果
2. itslist or []的作用原理
Python中or运算符遵循短路求值规则:如果左边表达式的布尔值为真,直接返回左边的值;否则返回右边的值。
- 空列表
[]的布尔值为False,所以当你使用默认的公共空列表作为参数传入时,itslist or []会直接返回右边新创建的空列表[] - 这个新的空列表是每次调用
__init__时临时生成的,每个实例拿到的都是独立的列表对象,互相之间不会干扰 - 修改
node_i自己的独立列表,自然不会影响到node_j的属性,问题就得到解决
补充最佳实践
更稳妥的可变默认参数写法是把默认值设为None,再判断初始化:
def __init__(self, data, itslist=None): self.data = data self.itslist = itslist if itslist is not None else []
这种写法可以兼容用户主动传入空列表的场景,不会像or []一样把用户主动传入的空列表也替换成新的列表。
内容的提问来源于stack exchange,提问作者John A.
相关产品推荐
相关产品推荐

