dict.setdefault() 用法

setdefault 是Python中字典的一个方法,用于在字典中查找指定键,如果键存在,则返回对应值(而不是指定的默认值);如果键不存在,则在字典中添加该键,并将其值设置为指定的默认值

dict.setdefault(key, default_value)

其中,key为要查找或添加的键,default_value为键不存在时设置的默认值(若省略,默认None)

d = {}
d.setdefault("list", []).append(1)
d.setdefault("list", []).append(2)
print(d)  # 输出:{"list": [1, 2]}
# 为字典d添加一个键'list',并将其值设置为一个空列表
# 使用列表的append方法向该列表中添加元素1和2

底层原理

Python中字典是一种无序的键值对集合,它的底层实现是通过拉链法实现的哈希表

  • 什么是哈希表?一种根据关键字直接访问内存位置的数据结构,通过哈希函数将关键字映射到对应的内存位置
  • 什么是拉链法(chaining)?每个哈希桶中存储一个链表, 哈希值相同的键值对会被插入到同一个链表中。当需要查找或插入一个键值对时,先计算出该键的哈希值,然后根据哈希值找到对应的哈希桶,再在该哈希桶对应的链表中查找或插入键值对
  • 什么是哈希桶(bucket)?是哈希表中存储元素的容器,是一个动态数组,每个元素都是一个链表,链表中的每个节点都是一个键值对
    • 哈希桶的大小通常是一个质数,这是为了保证哈希函数的均匀性和哈希表的性能。如果哈希桶比较小,会导致哈希冲突(hash collision)的概率增大,从而降低哈希表的性能;如果哈希桶比较大,会浪费内存空间
    • 哈希桶的大小是根据哈希表的负载因子(load factor)和哈希表中元素数量来计算的。同时是动态调整的,当哈希表中元素数量达到一定阈值时,会自动扩容哈希表,增加哈希桶的数量,在保证哈希函数均匀性和哈希表性能的同时,提高哈希表的存储容量

setdefault方法的底层实现步骤:

  1. 计算要查找或添加的键的哈希值,找到对应的哈希桶
  2. 遍历哈希桶对应的链表,查找是否有键与要查找或添加的键相同
  3. 如果找到了相同的键,则返回该键对应的值
  4. 如果没有找到相同的键,则在链表头部添加一个新的键值对,并将键的值设置为默认值,返回默认值作为该键的值

与 dict.get() 的区别

dict.get时:

  • 若get的键存在,则返回对应键的value,若不存在则返回设置的default的值,默认为None
  • 字典中的键值不会发生任何变化

dict.setdefault时:

  • 若setdefault的键存在,则返回对应键的value,若不存在则返回设置的default的值,默认为None
  • 同时,字典中会将该键及设置的默认值添加到字典中

例1:添加一个新键和默认值 

d = {"a": 1, "b": 2}
d.get("c", 3)
print(d)  # 输出:{'a': 1, 'b': 2}

d = {"a": 1, "b": 2}
d.setdefault("c", 3)
print(d)  # 输出:{'a': 1, 'b': 2, 'c': 3}
# 字典d本来并没有键为'c'的元素,使用setdefault方法可以添加一个新的键'c'和默认值3

例2:修改已有键的默认值

d = {"a": 1, "b": 2}
d.get("a", 3)
print(d)  # 输出:{"a": 1, "b": 2}

d = {"a": 1, "b": 2}
d.setdefault("a", 3)
print(d)  # 输出:{"a": 1, "b": 2}
# 字典d已经有键'a',使用setdefault方法仍然会返回键'a'对应的值1,而不会修改它的默认值

例3:可以省略默认值参数

d = {"a": 1, "b": 2}
d.get("c")
print(d)  # 输出:{"a": 1, "b": 2}

d = {"a": 1, "b": 2}
d.setdefault("c")
print(d)  # 输出:{"a": 1, "b": 2, "c": None}
# 省略了默认值参数,此时默认值为None

案例

我有一个字典,为用户评分数据,其中大写字母代表用户user,小写字母代表物品item:

user_score_dict = {
    'A': {'a': 3.0, 'b':4.0, 'c':0.0, 'd':3.5, 'e':0.0},
    'B': {'a': 4.0, 'b':0.0, 'c':4.5, 'd':0.0, 'e':3.5},
    'C': {'a': 0.0, 'b':3.5, 'c':0.0, 'd':0.0, 'e':3.0},
    'D': {'a': 0.0, 'b':4.0, 'c':0.0, 'd':3.5, 'e':3.0},
}

基于用户评分数据,构建共现矩阵,代码如下:

  • 什么是共现矩阵?行和列都代表物品a~e,元素代表同时喜欢两个物品的用户数
  • 显然,共现矩阵对角线全为0,且为对称矩阵
item_user_count = dict()   # 每个物品有多少用户产生过行为
count = dict()   # 共现矩阵

for user, item in user_score_dict.items():
    for i in item.keys():
        item_user_count.setdefault(i, 0)
        if user_score_dict[user][i] > 0.0:
            item_user_count[i] += 1
        for j in item.keys():
            count.setdefault(i, {}).setdefault(j, 0)
            if (user_score_dict[user][i] > 0.0
            and user_score_dict[user][j] > 0.0
            and i != j):
                count[i][j] += 1

结果如下:

item_user_count:  {'a': 2, 'b': 3, 'c': 1, 'd': 2, 'e': 3}
# a物品被A和B两个用户交互过,所以为2,以此类推

count:  {'a': {'a': 0, 'b': 1, 'c': 1, 'd': 1, 'e': 1}, 
         'b': {'a': 1, 'b': 0, 'c': 0, 'd': 2, 'e': 2}, 
         'c': {'a': 1, 'b': 0, 'c': 0, 'd': 0, 'e': 1}, 
         'd': {'a': 1, 'b': 2, 'c': 0, 'd': 0, 'e': 1}, 
         'e': {'a': 1, 'b': 2, 'c': 1, 'd': 1, 'e': 0}}
# 同时喜欢b和d的用户为A和D,有2个,所以为2,且对称,以此类推

在此基础上,得到物品之间的相似度矩阵,代码如下:

itemSim = dict()
for i, related_items in count.items():
    itemSim.setdefault(i, {})
    for j, cuv in related_items.items():
        itemSim[i].setdefault(j, 0)
        itemSim[i][j] = cuv / item_user_count[i]   # 同时喜欢物品i和j的用户数 / 喜欢物品i的用户数
        # 该公式可以理解为:喜欢物品i的用户中,有多少比例的用户也喜欢物品j

此处也可以写为:

for i, related_items in count.items():
    for j, cuv in related_items.items():
        itemSim.setdefault(i, {}).setdefault(j, 0)
        itemSim[i][j] = cuv / item_user_count[i]

结果如下:

itemSim:  
{'a': {'a': 0.0, 'b': 0.5, 'c': 0.5, 'd': 0.5, 'e': 0.5}, 
 'b': {'a': 0.3333333333333333, 'b': 0.0, 'c': 0.0, 'd': 0.6666666666666666, 'e': 0.6666666666666666}, 
 'c': {'a': 1.0, 'b': 0.0, 'c': 0.0, 'd': 0.0, 'e': 1.0}, 
 'd': {'a': 0.5, 'b': 1.0, 'c': 0.0, 'd': 0.0, 'e': 0.5}, 
 'e': {'a': 0.3333333333333333, 'b': 0.6666666666666666, 'c': 0.3333333333333333, 'd': 0.3333333333333333, 'e': 0.0}}

参考

python 中的 setdefault 方法详解、底层原理和用法-CSDN博客

Python中dict.setdefault的用法-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cheer-ego

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值