Dream&Trace blog

9月 04, 2018

当函数拥有一个可变类型的默认参数..

众所周知,python中的数据类型分为可变(mutable)和不可变(immutable)两种类型,这里暗含一个巨大的坑就是当函数的默认参数为可变(mutable)类型时,函数的运行结果可能会出乎你的意料,让我们来看一个例子:

def generateCommand(baseCommand=[]):
    # read config and generate command option
    args = ['-a', 'This is', '-b', 'command option']
    baseCommand.extend(args)
    return baseCommand

generateCommand() # ['-a', 'This is', '-b', 'command option']
generateCommand() # ['-a', 'This is', '-b', 'command option', '-a', 'This is', '-b', 'command option']

可以看出,默认参数只会运算一次,而不是每次被调用时都会重新运算,而baseCommand是一个可变类型,导致如果没有赋值,每次新的计算时都不会重新将其赋值为空列表.

怎样避免?

我们定义默认参数时应该尽量避免使用可变参数,比如像下面这样:(如果一定需要则需要写明注释,防止其他人调用接口出错)

def generateCommand(baseCommand=None):
    if baseCommand is None:   # Can be written as 'baseCommand == None', but use 'is' faster.
        baseCommand = []
    # read config and generate command option
    args = ['-a', 'This is', '-b', 'command option']
    baseCommand.extend(args)
    return baseCommand

generateCommand() # ['-a', 'This is', '-b', 'command option']
generateCommand() # ['-a', 'This is', '-b', 'command option']

值得注意的是,对于None来说,因为其有且仅有一个,所以可以使用is None代替== None,而事实上使用is速度更快,因为is是一个快速的id比较,而==需要调用内置函数__eq__()并查找被比较的值进行比较。