一.介绍
Dict(字典)与Java中的Map接口相似,很多想法可以直接转移过来。
创建dict:
python
hash1={ }
hash2=dict()
key要是不可变的数据类型,但是value可以是任意一种python类型。
下面例子中使用的数据都是这一个:
python
hash={
"id":1,
"name":"Tom"
}
二.常用方法
|----------------------|------------------------------------------------------|
| clear() | 删除字典内所有元素 |
| copy() | 返回一个字典的浅复制 |
| fromkeys(seq[,val) | 创建一个新字典,以序列 seq 中元素做字典的键,val 为字典所有键对应的初始值 |
| get(key) | 返回指定键的值,如果值不在字典中返回default值 |
| has_key(key) | 如果键在字典dict里返回true,否则返回false。Python3 不支持。 |
| items() | 以列表返回可遍历的(键, 值) 元组数组 |
| keys() | 以列表返回一个字典所有的键 |
| setdefault(key) | 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
| update(dict2) | 把字典dict2的键/值对更新到dict里 |
| values() | 以列表返回字典中的所有值 |
| pop(key[,default]) | 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。 |
| popitem() | 返回并删除字典中的最后一对键和值 |
除了使用一些方法,也可以直接使用"下标"这种方式访问或操作元素:
python
# in 判断in前面的key是不是在集合中
print("id" in hash)
# 通过key取value
print(hash["id"])
# 如果新增的key没在集合中,添加新的
hash["class"]=1
# 如果新增的key已经存在在集合中,更新key的value
hash["id"]=2
使用小技巧:字典解包
举一个连接数据库的例子方便理解:
python
config = {
"host": "localhost", # 数据库主机地址(本地一般为localhost)
"port": 3306, # 端口号(默认3306)
"user": "root", # 用户名
"password": "123456", # 密码(替换为你的实际密码)
"database": "test", # 要连接的数据库名(需提前创建)
"charset": "utf8mb4" # 字符集,支持中文
}
def connect_db():
try:
# 建立连接
conn = pymysql.connect(**config)
except pymysql.MySQLError as e:
print(f"数据库连接失败:{e}")
"""
conn = pymysql.connect(**config)等价于:
conn = pymysql.connect(
host="localhost",
port=3306,
user="root",
password="123456",
database="test_db",
charset="utf8mb4"
)
"""
三.Pythonic技巧
1.在检索 dict 值时提供默认参数
先看一下根据 key 获取 value 的两种方式:
python
# 第一种
value1 = hash["id"]
print(value1)
# 第二种
value2 = hash.get("name")
print(value2)
对于第一种,如果说字典里没有这个 key,那么会直接报错;
对于第二种,如果说字典里没有这个 key,那么获取到的 value 就是 None。
但是在应用,如果我们想要检索 dict 值,存在就取这个 key 的 value,不存在就取一个默认值。
如果使用第二种方式获取,那么要写一些逻辑判断:
python
data = None
if "name" in hash:
data = hash["name"]
else:
data = "Default"
但是,我们可以使用提供默认参数的方法来简化:
python
data = hash.get("name","Default")
这样写是不是就简洁很多了。
2.字典模拟 switch-case
python 中没有内置的 switch-case 语句,如果想要模拟其效果,就要使用 if-elif-else 来实现。
其实可以使用字典来实现的,核心思路如下:将 case 条件作为字典的 key,将 case 对应的执行逻辑(如函数、表达式)作为字典的 value,通过 "键查找" 替代 case 匹配,实现分支跳转。
python
def switch_calc_short(operation, a, b):
calc_dict = {
"+": lambda x, y: x + y,
"-": lambda x, y: x - y,
"*": lambda x, y: x * y,
"/": lambda x, y: x / y if y != 0 else "除数不能为0"
}
return calc_dict.get(operation, lambda x, y: "无效操作符")(a, b)
print(switch_calc_short("*", 3, 4))
3.通过字典推导来优化 dict 构造
字典推导式的语法如下:
python
# 语法:{key表达式: value表达式 for 变量 in 可迭代对象 if 条件判断}
new_dict = {k: v for 变量 in 可迭代对象 if 条件}
举个例子:
python
list_of_users =[User('KaKa',"kaka@local"),User('JoJo',"jojo@local")]
# 循环
emails_for_user ={}
for user in list_of_users:
if user.email:
emails_for_user[user.name]=user.email
# 推导式
emails_for_user = {user.name: user.email for user in list_of_users if user.email}
4.排序字典的方法
根据键、值或其他相关属性的某些条件来实现字典中元素的自定义排序。
但是用注意,字典本身是键值对,排序需要将其转化为可迭代的键/值/键值对序列(使用items()),再用 sorted() 。
可以使用 sorted 函数进行排序,默认是根据key进行排序:
python
d={'a':400,'c':200,'b':300,'d':100}
print(sorted(d.items()))
# output: [('a', 400), ('b', 300), ('c', 200), ('d', 100)]
根据value进行排序:
python
# 正序
print(sorted(d.items(),key=lambda x:x[1]))
print(sorted(d.items(),key=operator.itemgetter(1)))
# 逆序
print(sorted(d.items(),key=lambda x:x[1],reverse=True))
print(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
想要实现自定义排序就要使用lambda表达式
5.合并字典的方法
合并字典最简单的方法就是使用update(),update()会遍历字典,然后将这个字典里的内容添加到结果字典里,这也说明了一件事,如果存在重复的key,那么只会保留最后的value值。
python
fruit_price_a = {
"apple": 2.5,
"banana": 1.2,
"cherry": 3.0}
fruit_price_b = {
"banana": 1.0,
"dragonfruit": 5.0,
"elderberry": 4.0}
combined_fruit_price = {}
combined_fruit_price.update(fruit_price_a)
combined_fruit_price.update(fruit_price_b)
print(combined_fruit_price)
# Output: {'apple': 2.5, 'banana': 1.0, 'cherry': 3.0, 'dragonfruit': 5.0, 'elderberry': 4.0}
这里就可以注意到,香蕉的价格是1而不是1.2。
除了使用update(),还可以使用内置的 dict() 方法合并几个字典,并使用 ** 运算符来解包对象。
python
combined_fruit_price = {**fruit_price_a, **fruit_price_b}
print(combined_fruit_price)
使用 ** 运算符还可以在大型字典的情况下加快速度,因为它在语言结构本身中进行了优化。
6.优雅打印字典
第一种,使用 json.dumps() :
python
print(json.dumps(book, indent=4, sort_keys=False))
json 包中的方法仅适用于 dict 仅包含原始数据类型的情况,如果在字典中存储诸如函数之类的实体,就不能处理了。使用 json.dumps() 的另一个缺点是它不能字符串化复杂的数据类型,比如集合。
第二种,使用 pprint :
python
book = {'name': 'The Great Gatsby',
'author': 'F. Scott Fitzgerald',
'year': 1925,'info': {'publisher': 'Charles Scribner\'s Sons',
'pages': 218,
'language': 'English'}}
pprint(book, indent=4,sort_dicts=False)
与 json.dumps() 相比,pprint 在视觉上并不能很好地表示嵌套结构。
四.dict 子类
1.defaultdict 带默认值字典
defaultdict 是 python 标准库 collections 提供的增强版字典,与普通字典不同的是,其在访问不存在的键时会自动生成一个默认值。
这里不要和普通字典的 get 方法设置默认值弄混,get方法是当访问一个不存在的 key 时,会返回默认值,但是不会创建新的 key。而使用 defaultdict 时会自动创建一个新的 key。
对于一些统计分组处理数据,使用 defaultdict 比较方便:
python
# 统计字符串s中每个字符出现的次数
s = "abcdefg"
d = defaultdict(int)
for key in s:
d[key]+=1
print(d)
2.OrderedDict 有序字典
在 Python 2 和更早的版本中,字典被实现为简单的哈希表,可以存储键值对。当检索键列表时,无法保证或指定它们返回的顺序。在这种情况下,Python 中标准库的集合模块提供了 OrderedDict 实现,该实现保留了字典中插入元素的顺序,并在检索键时返回相同的顺序。
在 Python 3 及更高版本中,排序功能已包含在标准 dict 实现中。 Python 3 中的字典保留了元素的插入顺序。
3.ChainMap 链式字典
ChainMap 将多个字典穿成一条链。
使用 ChainMap 进行查找时,从左到右依次搜索底层字典,直到找到键。如果有多次出现,则只返回第一次出现。插入、更新和删除仅影响添加到链中的第一个映射。
下面举个例子对上面所说进行测试:
python
# 定义
m1 = {'a': 1, 'b': 2, 'c': 13}
m2 = {'c': 3, 'd': 4, 'e': 5}
cmap = ChainMap[m1, m2]
python
# 如果有多次出现,则只返回第一次出现的值
print(cmap['c']) # 输出 13
python
# 插入、更新和删除仅影响添加到链中的第一个映射
cmap['f'] = 6
cmap['b'] = 20
del cmap['c']
print(cmap) # 输出: ChainMap({'a': 1, 'b': 20, 'f': 6}, {'c': 3, 'd': 4, 'e': 5})
4.Counter 计数器
对可迭代对象的元素频次进行统计,大量简化了代码
python
lst = ["a", "b", "a", "c", "a", "b", "d"]
cnt = Counter(lst)
print(cnt) # 输出:Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
下面介绍几个常用的方法:
1)most_common()
返回前 n 个出现次数最多的元素及频次,默认返回所有元素(按频次降序排列)
python
cnt = Counter(["a", "b", "a", "c", "a", "b", "d"])
# 获取前 2 个高频元素
print(cnt.most_common(2)) # 输出:[('a', 3), ('b', 2)]
2)elements()
生成一个迭代器,按元素的频次重复生成元素
python
cnt = Counter(a=3, b=2, c=1)
# 转为列表查看
elements = list(cnt.elements())
print(elements) # 输出:['a', 'a', 'a', 'b', 'b', 'c'](顺序按插入顺序,频次对应重复次数)
3)update()
python
cnt = Counter(a=2, b=1)
# 传入可迭代对象,累加频次
cnt.update(["a", "c", "a"]) # "a" 频次 +2,"c" 新增(频次 1)
print(cnt) # 输出:Counter({'a': 4, 'b': 1, 'c': 1})
4)subtract()
python
cnt = Counter(a=4, b=3, c=1)
# 传入可迭代对象,递减频次
cnt.subtract(["a", "b", "b"]) # "a" 频次 -1,"b" 频次 -2
print(cnt) # 输出:Counter({'a': 3, 'b': 1, 'c': 1})