Python一个常见易犯的错误——函数可变参数

现在我们有一个函数,接受几个参数,其中一个参数是一个列表,如下:

def foo(a, bar=[]):
    bar.append(a)
    print(bar)

请问这个函数有错误吗?貌似没有,先运行试试:

foo(1)
# 输出
[1]  # 没问题

foo(1)
# 输出
[1, 1]     # 为什么会有两个1???

为什么在第二次运行foo(1)的时候bar会有两个1呢?这是因为在同一环境下,多次运行同一函数,函数参数仅初始化一次,因此对于这些可变的变量,每运行一次函数其值便会进行相应的更改。
下面对foo()函数进行一个修改:

def foo(a, bar=None):
    bar = [] if bar is None else bar
    bar.append(a)
    print(bar)

foo(1)
# [1]
foo(1)
# [1]

这时候每一次运行函数时,只要不是指定bar,bar都会被重新赋值为空列表。我们的问题也得到解决。

下面我们在来看看类中的相似情况:

class Bag:
    def __init__(self, contents=[]):
        self._contents = contents

    def add(self, something):
        self._contents.append(something)

# 第一次实例化类
A = Bag()
A.add(1)
print(A._contents)
# [1]
# 第二次实例化类
B = Bag()
B.add(2)
print(B._contents)
# [1, 2]

这里出现了与上面相同的情况,我们可以用相同的方法来解决:

class Bug:
    def __init__(self, contents=None):
        if contents is None:
            contents = []
        self._contents = contents

    def add(self, something):
        self._contents.append(something)

# 第一次实例化
A = Bug()
A.add(1)
print(A._contents)
# [1]
# 第二次实例化
B = Bug()
B.add(2)
print(B._contents)
# [2]

除了上面这种解决办法外,还有另一种解决办法,这种方法需要借助于attr库:

import attr

@attr.s
class A(object):
    _contents = attr.ib(default=attr.Factory(list))

    def add(self, x):
        self._contents.append(x)

a = A()
a.add(6)
print(a._contents)
# [6]
b = A()
b.add(666)
print(b._contents)
# [666]

参考:
Python陷阱:为什么不能用可变对象作为默认参数的值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。