文章首发于我的个人博客:欢迎大佬们前来逛逛
字典
创建字典的方式
字典由 关键字
和 值
组成。
由于关键字需要是索引,因此关键字必须是 **不可变类型。**通常为字符串或者数值,不能用列表做关键字。
字典的创建形式: {关键字: 值}
中间使用:分割
# 创建字典
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要方便的多。
创建一个可以自动将非字符串类型的键 转换为字符串类型并且进行查询,修改,删除的字典:
字典的构造过程:
- 首先通过构造函数进入
__init__
函数进行对象的构造,然后如果传入的dict不是空,则会进入update
函数进行插入键值对. - 进入到
update
函数后,首先检查传入的参数是否是Mapping
映射类型,如果是则进行下一步。 - 然后
键值对
的插入操作,进入到__setitem__
函数中,我们重写这个函数,把键全部改为str类型,因此我们无论输入的键是什么类型,都会是str类型
字典的 in 操作:
in
操作会执行__contains__
函数,因此在此函数中我们直接把key值变为str类型,然后使用内置的 in 进行查询
字典的查询操作:
- 通过 sdict[i] 查询一个值,首先会进入
__getitem__
函数中,如果查询的键不存在,则会进入到一个__missing__
函数中,该函数用来进行查询不到键时该如何操作。 - 在此函数中,我们判断如果这个不存在的键是str类型,则意味着这个键是合法的,但是却没有值,因此它确实没有这个值,抛出
KeyError
异常。 - 如果我们的键是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