python中函数的默认参数问题

  • L=[ ]
  • L=None
  • 解析
  • 要点

L=[ ]

在下面这段代码中,函数f1的默认参数L=[ ]

def f1(a, L=[]):
    L.append(a)
    return L
 
print(f1(1))
print(f1(2))
print(f1(3))

运行代码,输出为

[1]
 [1, 2]
 [1, 2, 3]

L=None

在下面这段代码中,函数f2的默认参数L=None

def f2(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

print(f2(1))
print(f2(2))
print(f2(3))

运行代码,输出为

[1]
 [2]
 [3]

解析

首先必须明确在python中所有的变量都是一个引用,引用保存的是对象的地址。比如 a=1 这个表达式做了两件事情,

1、创建一个对象,将1保存到这个对象中
2、将该对象的地址赋值给a。

这样一来,a就是一个引用,该引用保存的是新创建对象的地址。

又因为函数的默认参数只能在编译阶段被赋值,赋值完成后每次调用函数该参数都将以该值执行。所以f1f2的默认参数L都在编译阶段有了默认值,f1的L保存的是 [] 的地址,f2的L保存的是None的地址(也就是没有地址,即L没有保存任何值)。

当执行f1中的代码时,由于列表是可变数据类型,在函数中对L指向的对象的内容进行了修改,但L并没有改变,L中保存的依旧是原来那个对象的地址。
而在f2中,L一开始并不指向任何对象(L=None),执行过程中又指向了一个列表对象(L=[ ]),每次执行函数时默认参数只能取None,这就导致L每次都会从None变为指向一个新的列表对象,这个过程产生3个新的列表对象,每个列表对象中存储着一个不同的值,分别是[1], [2], [3]

要点

这个问题中需要掌握的要点有两个,分别是

1.python中的变量都是引用,引用保存的是一个地址,该地址指向某个对象。
2.函数的默认参数在编译阶段被赋值,之后每次调用函数时对应的默认参数值任为第一次被赋予的值。

f1中的L始终指向同一个对象(只是对象的内容发生了更改),f2中的L每次调用时都会被重置为None,在函数体中又会被修改。