Python 中不可变参数list做默认参数陷阱

本文深入探讨了Python函数中默认参数的使用误区,特别是在使用可变类型如列表作为默认参数时,可能导致的数据污染问题。文章通过示例代码展示了如何正确设置默认参数,避免后续调用时的意外行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

def extendlist(val, aaa=[]):
    print("运行前aaa的值是:",aaa,"aaa的id是:",id(aaa))
    aaa.append(val)
    print("运行后aaa的值是:",aaa)
    return aaa
list1 = extendlist(10)
print("list1的值和id是:",list1,id(list1))
list2 = extendlist(123, [])
print("list2的值和id是:",list2,id(list2))
list3 = extendlist('a')
print("list3的值和id是:",list3,id(list3))
print(list1,list2,list3)
print(id(list1),id(list3),id(list2))

运行结果如下:

运行前aaa的值是: [] aaa的id是: 99826056
运行后aaa的值是: [10]
list1的值和id是: [10] 99826056
运行前aaa的值是: [] aaa的id是: 99774216
运行后aaa的值是: [123]
list2的值和id是: [123] 99774216
运行前aaa的值是: [10] aaa的id是: 99826056
运行后aaa的值是: [10, 'a']
list3的值和id是: [10, 'a'] 99826056
[10, 'a'] [123] [10, 'a']
99826056 99826056 99774216

预期结果与实际不一致,原因是当我们调用函数时,如果有传递参数,则使用传递的参数,如果没有传递参数,就使用默认参数。而使用默认参数的时候,使用的是同一个,也就是保存的上一个默认参数值,通过最后的id可以发现,第三次调用参数时,默认参数的值是[10],而不是[].

为什么是同一个?

看如下代码:

def bar(args):
 
    args.append(1)
 
  
 
b = []
 
print(b)# 输出:[]
 
print(id(b)) # 输出:4324106952
 
bar(b)
 
print(b) # 输出:[1]
 
print(id(b))  # 输出:4324106952

Python 函数中,参数的传递本质上是一种赋值操作,而赋值操作是一种名字到对象的绑定过程,内存中绑定情况如下:

因为函数定义好之后,默认参数 aaa就会指向(绑定)到一个空列表对象,每次调用函数时,都是对同一个对象进行 append 操作。

详细请看:Python 函数中,参数是传值,还是传引用?

可以看到第一次调用时,list1确实是[10],但是当list3调用时,由于没有传递参数,使用上一次的值,所以此时aaa!=[],而是aaa=[10]

调用完成后,返回list3=[10,a],list1也是指向aaa的,所以此时list1的值会发生变化为list1=[10,a]

需要牢记的是默认参数不要用可变对象!!!

如果非要这样使用,可以在将aaa指向不可变对象None,在每次进行运算前进行判断:

def extendlist(val, aaa=None):
    if aaa==None:
        aaa=[]
    print("运行前aaa的值是:",aaa,"aaa的id是:",id(aaa))
    aaa.append(val)
    print("运行后aaa的值是:",aaa)
    return aaa
list1 = extendlist(10)
print("list1的值和id是:",list1,id(list1))
list2 = extendlist(123, [])
print("list2的值和id是:",list2,id(list2))
list3 = extendlist('a')
print("list3的值和id是:",list3,id(list3))
print(list1,list2,list3)
print(id(list1),id(list3),id(list2))
运行前aaa的值是: [] aaa的id是: 100677960
运行后aaa的值是: [10]
list1的值和id是: [10] 100677960
运行前aaa的值是: [] aaa的id是: 100626120
运行后aaa的值是: [123]
list2的值和id是: [123] 100626120
运行前aaa的值是: [] aaa的id是: 35127624
运行后aaa的值是: ['a']
list3的值和id是: ['a'] 35127624
[10] [123] ['a']
100677960 35127624 100626120

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值