使用可变类型作为缺省参数,自己练,还有在群里问, 搜索资料等了试了快两个小时, 初学比较慢记录下… 2019-04-15 15.40
代码举例:
第一次
>>> def func(item,item_list=[]):
item_list.append(item)
print(item_list)
>>> func('iphone')
['iphone']
>>> func('xiaomi',item_list=['oppo','vivo'])
['oppo', 'vivo', 'xiaomi']
>>> func('huawei')
['iphone', 'huawei']
>>> func('huawei',item_list=['oppo1','vivo1'])
['oppo1', 'vivo1', 'huawei']
第二次
>>> def func(item,item_list=[]):
item_list.append(item)
print(id(item_list))
print(item_list)
>>> func('xiaomi',item_list=['oppo','vivo'])
30203656
['oppo', 'vivo', 'xiaomi']
>>> func('huawei')
48941704
['huawei']
>>> func('huawei',item_list=['oppo1','vivo1'])
48891848
['oppo1', 'vivo1', 'huawei']
>>> func('xiaomi',item_list=[])
48941768
['xiaomi']
>>> func('huawei',item_list=[])
48941768
['huawei']
>>>
第三次
>>> def func(item,item_list=[]):
print (item_list)
item_list.append(item)
print(item_list)
>>> func('huawei')
[]
['huawei']
>>> func('huawei',item_list=['oppo1','vivo1'])
['oppo1', 'vivo1']
['oppo1', 'vivo1', 'huawei']
>>> func('iphone')
['huawei']
['huawei', 'iphone']
>>> func('huawei2',item_list=['oppo2','vivo2'])
['oppo2', 'vivo2']
['oppo2', 'vivo2', 'huawei2']
>>>
第四次 输出不一样的结果
>>> def func(item,item_list=None):
if item_list is None:
item_list = []
item_list.append(item)
else:
item_list.append(item)
return item_list
>>> func('phone')
['phone']
>>> func('c', ['a', 'b'])
['a', 'b', 'c']
>>> func('phone')
['phone']
>>>
第五次 输出不一样的结果 作用同四
>>> def func(item,item_list=[]):
item_list.append(item)
print(item_list)
item_list.clear()
>>> func('iphone')
['iphone']
>>> func('huawei')
['huawei']
>>> func('iphone',['A','B'])
['A', 'B', 'iphone']
>>> func('iphone',['A','B'])
['A', 'B', 'iphone']
>>>
第六次 输出不一样结果,作用同四,五
>>> def func(item,item_list=None):
if item_list is None:
item_list=[]
item_list.append(item)
return item_list
>>> func('a')
['a']
>>> func('a',['b','c'])
['b', 'c', 'a']
第六:不可变默认参数 实例
>>> def immutable_test(i = 1):
print('before operation', id(i))
i += 1
print('after operation', id(i))
return i
>>> print(immutable_test())
before operation 1398500368
after operation 1398500400
2
>>> print(immutable_test())
before operation 1398500368
after operation 1398500400
2
>>> print(immutable_test(i=2))
before operation 1398500400
after operation 1398500432
3
>>> print(immutable_test(2))
before operation 1398500400
after operation 1398500432
3
>>> print(immutable_test(3))
before operation 1398500432
after operation 1398500464
4
>>> id(immutable_test)
49303200
>>> id(immutable_test(2))
before operation 1398500400
after operation 1398500432
1398500432
>>> id(immutable_test(23))
before operation 1398501072
after operation 1398501104
1398501104
>>>
很明显,第二次调用时默认参数i的值不会受第一次调用的影响。因为i指向的是不可变对象,对i的操作会造成内存重新分配,对象重新创建,那么函数中i += 1之后名字i指向了另外的地址;根据默认参数的规则,下次调用时,i指向的地址还是函数定义时赋予的地址,这个地址的值1并没有被改变。
其实,可变默认参数和不可变默认参数放在这里讨论并没太大的价值,就像其他语言中所谓的值传递还是引用传递一样,不只会对默认参数造成影响。
总结:
最佳实践
不可变的默认参数的多次调用不会造成任何影响,可变默认参数的多次调用的结果不符合预期。那么在使用可变默认参数时,就不能只在函数定义时初始化一次,而应该在每次调用时初始化。
最佳实践是定义函数时指定可变默认参数的值为None,在函数体内部重新绑定默认参数的值。以下是对上面的两个可变默认参数示例最佳实践的应用:
def good_append(new_item, a_list = None):
if a_list is None:
a_list = []
a_list.append(new_item)
return a_list
print(good_append('1'))
print(good_append('2'))
print(good_append('c', ['a', 'b']))
import datetime as dt
from time import sleep
def log_time(msg, time = None):
if time is None:
time = dt.datetime.now()
sleep(1)
print("%s: %s" % (time.isoformat(), msg))
log_time('msg 1')
log_time('msg 2')
log_time('msg 3')