默认值参数只被初始化一次,使用可变序列为参数带来的困扰!
def demo(newitem,old_list=[]):old_list.append(newitem)
return old_list
print(demo('a'))
print(demo('b'))
上面代码因默认值参数默认值被赋成一个空列表,而使调用出现问题,可用下面代码修正。
def demo(newitem,old_list=None):
if old_list is None:
old_list=[]
old_list.append(newitem)
return old_list
print(demo('a'))
print(demo('b'))
为什么给默认参数赋值成None可以解决这个问题了呢? 因为列表是可变类型,而 None 是不可变类型 list 有方法来改变它本身,NoneType 没有 因为函数只在最开始定义的时候进行一次解析,在这时为默认值参数分配id。因此每次调用的时候都会去扫描此id下的内容
再来说一下可变量类型和不可变类型,这里若默认值参数是不可变类型,在函数中对其进行修改实际上是被认为重新定义了一个同名变量(这一点可以print变量的id看一下就知道了),而若默认值参数是可变类型,在函数中对其进行修改操作就是对其本身进行的操作,不会被认为是重新定义了一个同名变量。
这是为什么呢?
答案如下:
对于不可变类型的变量,若是在函数内部进行修改的话,会有歧义,无法识别到底是修改同名的全局变量,还是定义一个同名的局部变量(因为修改和定义方式是一样的)。因此在函数内若使用不可变类型的全局变量时需要使用global进行明确指出。
对于可变类型,则不存在这种歧义,若是在函数内部修改一个与全局变量同名的变量,不会被认为是要创建一个同名的局部变量(因为修改和定义方式是不一样的),当在函数内没有定义一个与全局变量同名的局部变量,那么修改一个同名的变量时,能够明确就是修改全局变量。
因此,若是打算用一个默认值的可变类型是不行的。
实际上你的第二种写法,完全就是在函数中重新创建了一个同名变量,因为默认值没指定类型,调用参数的时候可以掺进来任何类型的参数,若没有传进来该参数,则会执行if语句,定义一个类型,这就是创建了一个变量。
页:
[1]