Python函数默认参数为空列表

本文通过示例解释了Python函数默认参数为何不应使用可变对象如列表。在函数调用中,由于列表是可变对象,多次调用会共享同一列表实例。正确的做法是使用不可变对象作为默认参数。

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

示例: 

-测试命名比较随意-

# foo?对象
def add(foo=[]):
    """传入的参数为变量foo,指向的[]在定义函数之前创建,而不是每次执行前重新创建一个新列表对象"""
    print(id(foo))
    foo.append('end')
    print(foo)  # 变量foo依然指向添加了元素之后的列表对象


def add_2(foo=5):
    """传入的参数为变量foo,指向的5(int)在定义函数之前创建,同样不是每次执行前重新创建一个int对象"""
    print(foo, id(foo))
    foo += 1
    print(foo, id(foo))  # 创一个int对象:6,变量foo重新指向6


# 如果在函数外先定义好传入的参数呢?
_test = []  # 创建一个新的空列表对象
_test2 = 5  # 定义的变量依然指向之前创建的5


# foo?_test2?对象
def add_3(foo=_test):
    print(id(foo))
    foo.append('end')
    print(foo)


def add_4(foo=_test2):
    """5和6依然为第一次创建的对象"""
    print(foo, id(foo))
    foo += 1
    print(foo, id(foo))


add()  # 4386785416 ['end']
add()  # 4386785416 ['end', 'end']  没有重新创建一个空列表对象
add_2()  # 5 4384690336    6 4384690368
add_2()  # 5 4384690336    6 4384690368

# 函数外定义好参数,其实和上面的没有区别,只是中间多了一个变量的引用而已
add_3()  # 4386785352 ['end']
add_3()  # 4386785352 ['end', 'end']
add_4()  # 5 4384690336    6 4384690368
add_4()  # 5 4384690336    6 4384690368

函数add()第二次执行的时候,没有重新创建一个新的空列表对象,而是传入了第一次执行时创建的那个列表对象,原因是函数add()的参数是变量foo,foo储存的是第一次创建的列表的实体地址(python是根据变量中储存的实体地址去查找对象的:寻址),而列表是可变对象,当列表中添加了新的元素之后,对象的实体地址并没有发生变化,变量foo中储存的地址也不会发生变化,所以第二次执行的时候传入的foo变量依然还是第一次的那个列表对象。如下图:

总结:

  • 在一个脚本运行的环境中,不可变对象(int等)应该只会创建一次,定义不同的变量的话,不同变量只是储存对象实体的地址,只是增加(_test2增加了一个对象5的引用)或者改变(函数add()中的变量foo,开始指向对象5,+1后指向对象6)变量的引用而已,不会重新再创建一个对象(测试中的int对象5和6,至始至终对象实体没有发生变化)
  • 重新执行脚本后所有对象会重新创建
  • 函数的默认参数应该为不可变对象,测试中的函数add()和add_3()传递列表参数不可取,正确姿势如下:
def add_end(foo=None):
    if foo is None:
        # 执行时会重新创建一个新的空列表对象
        foo = []
    foo.append('END')
    return foo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值