关于python中函数的默认参数

先上代码 

def dict_update(k, v, dic={}):
    print(id(dic))
    dic[k] = v
    print(dic)


print(id(dict_update))
dict_update('one', 1)

print(id(dict_update))
dict_update('two', 2)

print(id(dict_update))
dict_update('three', 3, {})

结果

139666338994376
139666339627656
{'one': 1}
139666338994376
139666339627656
{'two': 2, 'one': 1}
139666338994376
139666339627784
{'three': 3}

 

面试遇到这个题,我以为每次调用函数的时候,dic都初始化为{},后来发现原来不是这样的,

函数的定义相当于一次类型构造,默认值只在此时解析一次。 而函数调用时不会重新执行默认参数的构造。所以,如果使用了字典,列表这样的可变类型。 而又要在函数体内修改它,可能会出现意想不到的效果。

验证

def dict_update(k, v, dic={}):
    print(id(dic))
    dic[k] = v
    print(dic)


print(id(dict_update))
dict_update('one', 1)


def dict_update(k, v, dic={}):
    print(id(dic))
    dic[k] = v
    print(dic)


print(id(dict_update))
dict_update('two', 2)

print(id(dict_update))
dict_update('three', 3, {})

 结果

140286289041608
140286289674888
{'one': 1}
140286289040928
140286289675272
{'two': 2}
140286289040928
140286289674888
{'three': 3}

总结

  1.  函数的定义相当于一次类型构造,默认值只在此时解析一次

  2. 而函数调用时不会重新执行默认参数的构造
  3. 函数算是 function 的实例, 把 def func()理解成 func = new Function() ,此时该函数实例计数是 1 ,如果此时删除其引用 del func 或者给 func 赋值其他值,致使函数对象引用计数为0,那它就被回收了,同理的 class Test(object) 视为 Test = new type() ,它的引用计数同一般普通的变量计算方式一样,没什么特别的。所以只要引用计数不为 0,那它的生命周期就是整个程序的生命周期
  4. 函数也是对象,因此定义的时候就被执行,默认参数是函数的属性,它的值可能会随着函数被调用而改变 。其他对象不都是如此吗?
  5. 当python执行def语句时,它会根据编译好的函数体字节码和命名空间等信息新建一个函数对象,并且会计算默认参数的值。函数的所有构成要素均可通过它的属性来访问,比如可以用func name属性来查看函数的名称。所有默认参数值则存储在函数对象的 defaults _属性中,它的值为一个列表,列表中每一个元素均为一个默认参数的值
def dict_update(k, v, dic={}):
    dic[k] = v
    print(dic)



dict_update('one', 1)
print(dict_update.__defaults__)

dict_update('two', 2)
print(dict_update.__defaults__)

dict_update('three', 3, {})
print(dict_update.__defaults__)

dict_update('four', 4)
print(dict_update.__defaults__)

 结果

{'one': 1}
({'one': 1},)
{'two': 2, 'one': 1}
({'two': 2, 'one': 1},)
{'three': 3}
({'two': 2, 'one': 1},)
{'four': 4, 'two': 2, 'one': 1}
({'four': 4, 'two': 2, 'one': 1},)

由于第三个传入了dic的值,所以没有用默认值,其他全部都是默认值(定义函数时的那个字典对象,只是由于调用使字典对象的值发生了变化,但字典对象并没变) 

参考

猜你喜欢

转载自blog.csdn.net/q389797999/article/details/89319137