默认参数 d = {} 的陷阱
- 问题需求
- 思路
- 代码实现
- 默认参数d = {}的陷阱
- 解决办法
- 1、在函数外为每个字符串创建空字典统计词频
- 2、函数改为每次调用时创建新字典,避免数据污染
- 举一反三
问题需求
统计两个字符串的中文词语出现次数
思路
先使用jieba库分词功能处理字符串,再用字典统计词频
代码实现
# 导包、设置变量
import jieba as j
str1 = "默认参数"*20
str2 = "默认变量"*10
print(str1)
print(str2)
输出
默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数
默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量
# 定义统计词频的函数
def get_amount(str_,d = {}):
for word in j.lcut(str_):
d[word] = d.get(word,0) + 1
return d
# 调用函数统计两个字符串词频
words_num1 = get_amount(str1)
words_num2 = get_amount(str2)
print(words_num1)
print(words_num2)
输出
Building prefix dict from the default dictionary ...
Dumping model to file cache C:\Users\walfar\AppData\Local\Temp\jieba.cache
Loading model cost 0.624 seconds.
Prefix dict has been built successfully.
{'默认': 30, '参数': 20, '变量': 10}
{'默认': 30, '参数': 20, '变量': 10}
最后统计结果是对两个字符串所有词语的词频统计
默认参数d = {}的陷阱
Python 函数中的默认参数会在函数定义时初始化一次,而非每次调用时重新创建。当连续调用 get_amount(str1)和get_amount(str2)时,第二次调用会 复用第一次调用后的字典,两次的返回值都是d,words_num1 和 words_num2指向的都是字典d的地址?
做个实验:
def test(d = {}):
d["666"] = d.get("666",0) + 1
return d
a = test()
print("第一次调用,变量a存储内容",a)
b = test()
print("第二次调用,变量a存储内容",a)
print("第二次调用,变量b存储内容",b)
c = test()
print("第三次调用,变量a存储内容",a)
print("第三次调用,变量b存储内容",b)
print("第三次调用,变量c存储内容",c)
print("a b c 三个变量的地址:","\n",id(a),"\n",id(b),"\n",id(c))
输出
第一次调用,变量a存储内容 {'666': 1}
第二次调用,变量a存储内容 {'666': 2}
第二次调用,变量b存储内容 {'666': 2}
第三次调用,变量a存储内容 {'666': 3}
第三次调用,变量b存储内容 {'666': 3}
第三次调用,变量c存储内容 {'666': 3}
a b c 三个变量的地址:
2099268147584
2099268147584
2099268147584
解决办法
1、在函数外为每个字符串创建空字典统计词频
# 导包、设置变量
import jieba as j
str1 = "默认参数"*20
str2 = "默认变量"*10
print(str1)
print(str2)
words_num1 = {}
words_num2 = {}
# 定义统计词频的函数
def get_amount(str_,d):
for word in j.lcut(str_):
d[word] = d.get(word,0) + 1
get_amount(str1,words_num1)
get_amount(str2,words_num2)
print(words_num1)
print(words_num2)
输出
默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数
默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量
{'默认': 20, '参数': 20}
{'默认': 10, '变量': 10}
统计结果符合预期
2、函数改为每次调用时创建新字典,避免数据污染
# 导包、设置变量
import jieba as j
str1 = "默认参数"*20
str2 = "默认变量"*10
print(str1)
print(str2)
# 定义统计词频的函数
def get_amount(str_,d=None):
if d is None:
d = {}
for word in j.lcut(str_):
d[word] = d.get(word,0) + 1
return d
words_num1 = get_amount(str1)
words_num2 = get_amount(str2)
print(words_num1)
print(words_num2)
输出
默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数默认参数
默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量默认变量
{'默认': 20, '参数': 20}
{'默认': 10, '变量': 10}
结果同样符合预期
举一反三
默认参数 d = {} 有陷阱,那么默认参数为空字符串、空列表 string = “” list = [],是否同样存在陷阱?
# 任务要求 两两拼接字符串
str1 = "你干嘛"
str2 = "哎呦"
str3 = "诞生于1996"
str4 = "梦想做说唱领袖"
# 定义拼接字符串函数
def put_together(s1,s2,s=""):
s = s + s1+s2
return s
caixukun = put_together(str1,str2)
print(caixukun)
wangziyi = put_together(str3,str4)
print(wangziyi)
输出
你干嘛哎呦
诞生于1996梦想做说唱领袖
打印id
print(id(caixukun))
print(id(wangziyi))
2099268620528
2099362636720
不存在数据污染问题
默认参数 s=“” 的不存在陷阱?还是我的实验设置有问题?
下面测试默认参数为空列表的情况
# 任务要求 两两将字符串放入两个列表中
str1 = "你干嘛"
str2 = "哎呦"
str3 = "诞生于1996"
str4 = "梦想做说唱领袖"
# 定义拼接字符串函数
def put_in_list(s1,s2,ls = []):
ls.append(s1)
ls.append(s2)
return ls
caixukun = put_in_list(str1,str2)
print(caixukun,id(caixukun))
wangziyi = put_in_list(str3,str4)
print(wangziyi,id(wangziyi))
输出
['你干嘛', '哎呦'] 2099362695808
['你干嘛', '哎呦', '诞生于1996', '梦想做说唱领袖'] 2099362695808
默认参数为空列表的情况存在陷阱