本文给大家讲述的是python 默认参数问题的陷阱,有需要的小伙伴可以参考下
python 里面一个常见的陷阱就是函数的默认参数问题。如下:
def func(mylist = []):
mylist.append(1)
return mylist
以下的执行结果如下:
print func()
print func()
print func()
print func(['a'])
print func()
结果如下:
[1]
[1, 1]
[1, 1, 1]
['a', 1]
[1, 1, 1, 1]
如此结果, 前面三个可以看出 如果没有指定参数的话, 每次调用函数时候, 调
Python函数的默认参数是一个需要注意的重要概念,特别是在处理可变对象如列表、字典或类实例时。函数的默认参数在定义时被初始化,并且在整个函数生命周期内保持不变。这意味着,如果默认参数是一个可变对象,那么它在后续的函数调用中可能会保留之前的状态,导致非预期的行为。
在标题中提到的陷阱,可以通过以下示例来理解:
```python
def func(mylist = []):
mylist.append(1)
return mylist
print(func())
print(func())
print(func())
```
这段代码中,`func`函数的默认参数`mylist`是一个空列表。每次调用`func`而没有传递参数时,它都会使用同一个默认列表。因此,每次调用都会在列表末尾添加一个元素,导致多次调用后的结果不是独立的列表,而是共享同一个列表状态。这就是所谓的默认参数陷阱。
默认参数的值如果是不可变对象(如整数、字符串、元组),则不会引发这个问题,因为这些对象在修改时会创建新的对象,函数的默认参数依然保持不变。例如:
```python
def func2(var = 1):
var += 1
return var
print(func2())
print(func2())
```
在这个例子中,虽然每次调用`func2`时`var`看起来都在变化,但实际上每次调用都会创建一个新的整数对象,函数的默认参数`var`始终指向1。
然而,对于可变对象如列表,如果我们想要在函数内部创建新的列表,可以这样做:
```python
def func(mylist = None):
if mylist is None:
mylist = []
mylist.append(1)
return mylist
```
这样,如果`mylist`为`None`,函数会创建一个新的列表,避免了默认参数陷阱。
默认参数的一个常见应用是创建闭包,例如:
```python
def outer(i):
def inner(j):
return j * i
return inner
print([outer(i)(2) for i in range(4)])
```
在这个例子中,我们期望得到`[0, 2, 4, 6]`,但由于闭包的延迟绑定特性,实际得到的是`[6, 6, 6, 6]`,因为所有`inner`函数都引用了同一个变量`i`,即`i`在循环结束后最后的值。要解决这个问题,我们可以利用默认参数在定义时绑定`i`的值:
```python
def outer(i):
def inner(j, i=i):
return j * i
return inner
print([outer(i)(2) for i in range(4)])
```
现在,每个`inner`函数都有了自己的`i`值,结果就正确了。
此外,生成器表达式也可以用来创建不共享状态的闭包:
```python
def multipliers():
return (lambda x, i=i: i * x for i in range(4))
print([m(2) for m in multipliers()])
```
这里,生成器表达式确保了每个`lambda`函数都拥有独立的`i`值。
理解和妥善处理Python函数的默认参数,特别是涉及到可变对象时,是编写可预测、可维护代码的关键。了解这些陷阱可以帮助我们避免潜在的问题,并利用默认参数实现更高效的功能。