Python数据结构 - 字典

文章首发于我的个人博客:欢迎大佬们前来逛逛

@

字典

创建字典的方式

字典由 关键字 组成。

由于关键字需要是索引,因此关键字必须是 不可变类型。通常为字符串或者数值,不能用列表做关键字。

字典的创建形式: {关键字: 值} 中间使用:分割

# 创建字典
dic = {'k1':123, 'k2':234, 'k3':456}
print(dic)
# 修改字典值
dic['k2'] = 999
print(dic)
# 删除字典键值对
del dic['k2']
print(dic)
-----------
{'k1': 123, 'k2': 234, 'k3': 456}
{'k1': 123, 'k2': 999, 'k3': 456}
{'k1': 123, 'k3': 456}

字典的关键字可以组成列表:

list 形成列表, sorted 对列表排序

# 返回所有关键字组成的列表
print(list(dic.keys()))
print(sorted(list(dic.keys())))
for key in dic:
	print(dic[key], end=' ')
--------
['k1', 'k3', 'k2']
['k1', 'k2', 'k3']
123 456 666

使用 dict 直接创建字典:

dict中形成字典的大括号既可以使用 {} 也可以使用 [] ,但是键值对必须()


dic = dict({('sape', 4139), ('guido', 4127), ('jack', 4098)})

使用字典推导式创建字典:以任意键值对作为元素的可迭代对象中构建出字典。

dd1 = [
	('ylh',99),
	('lxy',90),
	('wjh',95),
	('lpo',65)
]
dd2 = {name:score for name,score in dd1}
print(dd2)

dd3 = {name:score for name,score in dd2.items() if score>=80}
print(dd3)

dic = {x:x**2 for x in range(10)}

dict 创建关键字都是字符串类型的字典:

字面语法与构造方法:

# 创建字典的方式
d1 = dict(one=1,two=2,three=3)
d2 = {'one':1,'two':2,'three':3}
d3 = dict(zip(['one','two','three'],[1,2,3]))
d4 = dict([('one',1),('two',2),('three',3)])
d5 = dict({'one':1,'two':2,'three':3})
print(d1==d2==d3==d4==d5)
-----------
True

setdefault

一个统计文本中所有单词出现的行列坐标的程序:

# setdefault
import re
WORD_RE = re.compile(r'\w+')
words_dict = {}
fp = open('english.txt','r')
for row,line in enumerate(fp,1):
	for match in WORD_RE.finditer(line):
		word = match.group()
		col = match.start()+1
		ls = (row,col)
		words_dict.setdefault(word,[]).append(ls)

for word in sorted(words_dict):
	print(word,words_dict[word])

defaultdict

提供了一个为找不到的键创建默认值的方法:

如果index没有word的值,则会调用 default_factory 为查询不到的键创建一个值,这个值在这里是一个 空列表 ,然后赋值给 words_dict[word],并且是一个引用,然后可以执行 append的操作。

如果在创建 defaultdict 的时候没有指定 default_factory,查询不存在的键会触发 KeyError

import re
WORD_RE = re.compile(r'\w+')
words_dict = collections.defaultdict(list) # defaultdict
fp = open('english.txt','r')
for row,line in enumerate(fp,1):
	for match in WORD_RE.finditer(line):
		word = match.group()
		col = match.start()+1
		ls = (row,col)
		words_dict[word].append(ls)

for word in sorted(words_dict):
	print(word,words_dict[word])

字典的变种

collections.OrderedDict 添加键的时候会保持顺序,保持迭代顺序也始终是一致的。

它具有 popitem 方法,其默认删除最后一个元素,如果设置 last=False,则删除的就是第一个元素,并且返回这个值

res = collections.OrderedDict({'one':1,"three":3,"two":2})

collections.ChainMap 可以把多个映射集合到一个视图里面

在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止


collections.Counter 可以产生一个具有计数功能的映射,

使用 update 可以进行更新

import collections
res = collections.Counter('abcdefgffaa')
print(res)
res.update('aaa')
print(res)
----------
Counter({'a': 3, 'f': 3, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'g': 1})
Counter({'a': 6, 'f': 3, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'g': 1})

collections.UserDict 把Dict用纯python纯写的,UserDict非常适合于继承。

可以说它封装了字典对象,简化了字典子类化

它具有一个 data 属性,其中存储着 Dict真正的数据,这才是一个真正的字典。


子类化UserDict

如果要创建自定义类型,则使用 UserDict 比使用普通的dict要方便的多。

创建一个可以自动将非字符串类型的键 转换为字符串类型并且进行查询,修改,删除的字典:

字典的构造过程:

  1. 首先通过构造函数进入 __init__ 函数进行对象的构造,然后如果传入的dict不是空,则会进入 update 函数进行插入键值对.
  2. 进入到 update 函数后,首先检查传入的参数是否是 Mapping 映射类型,如果是则进行下一步。
  3. 然后 键值对 的插入操作,进入到 __setitem__ 函数中,我们重写这个函数,把键全部改为str类型,因此我们无论输入的键是什么类型,都会是str类型

字典的 in 操作:

  1. in 操作会执行 __contains__ 函数,因此在此函数中我们直接把key值变为str类型,然后使用内置的 in 进行查询

字典的查询操作:

  1. 通过 sdict[i] 查询一个值,首先会进入 __getitem__ 函数中,如果查询的键不存在,则会进入到一个 __missing__ 函数中,该函数用来进行查询不到键时该如何操作
  2. 在此函数中,我们判断如果这个不存在的键是str类型,则意味着这个键是合法的,但是却没有值,因此它确实没有这个值,抛出 KeyError 异常。
  3. 如果我们的键是int类型,但是str(int)的键却是有值的,因此将key 转换为 str(key) 然后再次进入到 __getitem__ 中查询类型为str的键是否存在值,如果没有,则执行 2操作,抛出异常,然后退出。如果有值,则返回。
class StrKeyDict(collections.UserDict):
	def __missing__(self, key):
		if isinstance(key, str):
			raise KeyError
		return self[str(key)]

	def __contains__(self, key):
		return str(key) in self.data

	def __setitem__(self, key, value):
		self.data[str(key)] = value

sdict = StrKeyDict({'1':1111,'2':2222,'3':3333,'4':4444})
print(1 in sdict)
for i in range(1,5): # i是 int类型
	print(sdict[i])
----------
True
1111
2222
3333
4444

不可变映射类型

字典都是可变的,有没有一种字典是不可变的呢?

types 模块的 MappingProxyType 提供了这样一种方法。

在MappingProxyType对象中执行更改操作会出错,因为它返回的只是一个只读视图

但是在源对象中更改是允许的。对原映射做出了改动,我们通过这个视图可以观察到。

from types import MappingProxyType
cs_dict = MappingProxyType(sdict)
sdict['2'] = 3333 # OK
print(cs_dict)
cs_dict['1'] = 555 # ERROR
---------
{'1': 1111, '2': 3333, '3': 3333, '4': 4444}
Traceback (most recent call last):
  File "F:\code\python\review\Fluent_Python\demo3.py", line 98, in <module>
    cs_dict['1'] = 555
TypeError: 'mappingproxy' object does not support item assignment

posted @ 2023-04-19 17:15  hugeYlh  阅读(8)  评论(0编辑  收藏  举报