字典类似Java中的Map,字典中的键可以是数字、字符串甚至是元组。

它们有一个共同特点就是不可变的,更进一步说,是可散列的数据类型。

可散列的: 在对象的生命周期汇总,它的散列值(hash code)是不变的,而且这个对象需要实现__hash__()__eq__()方法。如果两个可散列对象是相等的,那么它们的散列值一定是一样的。

上面说元组可以作为键是有个前提的,就是元组包含的所有元素都是可散列的情况下:


In [33]: tl = (1,2,[30,40])                                                                                  In [34]: hash(tl)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-34-b7b49ff1c689> in <module>
----> 1 hash(tl)TypeError: unhashable type: 'list'In [36]: d = {tl:'1'}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-8be9aeb1426b> in <module>
----> 1 d = {tl:'1'}TypeError: unhashable type: 'list'

一般用户自定义的类型都是可散列的,散列值是它们的id()函数返回的值。

创建和使用字典

>>> people = {'jack':34,'rose':25,'jack':36}
>>> people
{'rose': 25, 'jack': 36}>>> type(d)
dict

上面就是创建字典的方法,注意,字典中键是唯一的,我输入了两个’jack’,结果取的是后面输入的’jack’。

dict函数

也可以使用dict函数,通过其他映射(字典)或者(键,值)对的序列建立字典

>>> items = [('name','jack'),('age',24)]
>>> d = dict(items)
>>> d
{'age': 24, 'name': 'jack'}
>>> d['name']
'jack'

也可以通过关键字参数来创建字典:

>>> d = dict(name='rose',age=43)
>>> d
{'age': 43, 'name': 'rose'}

总结一下创建字典的方法:


In [54]: a = dict(one=1,two=2,three=3)                                                                       In [55]: b = {'one':1,'two':2,'three':3}                                                                     In [56]: c = dict(zip(['one','two','three'],[1,2,3]))                                                        In [57]: d = dict([('two',2),('one',1),('three',3)])                                                         In [58]: e = dict({'three':3,'one':1,'two':2})                                                               In [59]: a == b == c == d == e
Out[59]: True

字典推导

字典推导可以从任何以键值对作为元素的可迭代对象中构建出字典。
下面展示了如何把一个装满元组的列表变成两个不同的字典:

In [66]: DIAL_CODES = [  ...:  (86, 'China'), ...:   (91, 'India'), ...:    (1, 'United States'), ...:     (62, 'Indonesia'), ...:      (55, 'Brazil'), ...:       (92, 'Pakistan'), ...:        (880, 'Bangladesh'), ...:         (234, 'Nigeria'), ...:          (7, 'Russia'), ...:           (81, 'Japan'), ...:            ]                                                                                        In [67]: country_code = {country : code for code, country in DIAL_CODES} #country 作为键,code作为值
In [69]: country_code
Out[69]:
{'China': 86,'India': 91,'United States': 1,'Indonesia': 62,'Brazil': 55,'Pakistan': 92,'Bangladesh': 880,'Nigeria': 234,'Russia': 7,'Japan': 81}In [70]: {code : country.upper() for country, code in country_code.items() if code < 66}
Out[70]: {1: 'UNITED STATES', 62: 'INDONESIA', 55: 'BRAZIL', 7: 'RUSSIA'}

字典的基本操作

字典中的键可以是任意的不可变类型,比如浮点型、字符串或元组。

字典的基本操作很多方面与序列类似:

  • len(d) 返回d中项(键值对)的数量
  • d[k]返回k对应的值
>>> d
{'age': 43, 'name': 'rose'}
>>> d['age']
43
>>> d['a']
Traceback (most recent call last):File "<stdin>", line 1, in <module>
KeyError: 'a'

如果输入不存在的键,会报错。

  • d[k]=v将值v关联到键k上
>>> d['a'] = 1
>>> d
{'a': 1, 'age': 43, 'name': 'rose'}

可以关联一个不存在的键,那么就是添加一个新的键值对。如果关联已存在的键,则是覆盖。

  • del d[k]删除键为k的项
  • k in d检查d是否含有键为k的项

字典的格式化字符串

可以在%后面加上键:

>>> people
{'rose': 25, 'jack': 36}
>>> " rose's age is %(rose)s" % people #%(rose)s 在%s中间加入了(rose)
" rose's age is 25"

字典方法

  • clear
    用来清除字典中所有的项。这个是原地操作,也就是无返回值。
>>> d = {}
>>> d['name']='Jack'
>>> d
{'name': 'Jack'}
>>> d.clear()
>>> d
{}
  • copy
    返回一个具有相同键值对的新字典,该方法实现的是浅克隆。
>>> x = {'username': 'admin','machines': ['linux1','centos1','windows10']}
>>> y = x.copy()
>>> y['username'] = 'mlh'
>>> y['machines'].remove('linux1')
>>> y
{'username': 'mlh', 'machines': ['centos1', 'windows10']}
>>> x
{'username': 'admin', 'machines': ['centos1', 'windows10']}

可以看到,在副本中替换值的时候,原始字典不受影响,但是如果修改了某个值(原地修改),原始字典也会改变。

其实因为浅克隆拷贝的只是引用,替换值就是替换成了其他引用,是不会影响原始字典的。而修改值,修改的是同一个引用指向的内存空间,因此都会影响。

避免这个问题的一种方法就是深克隆:

>>> from copy import deepcopy
>>> d = {}
>>> d['names'] = ['Alfred','Bertrand']
>>> c = d.copy()
>>> dc = deepcopy(d)
>>> d['names'].append('Clive')
>>> c
{'names': ['Alfred', 'Bertrand', 'Clive']}
>>> dc
{'names': ['Alfred', 'Bertrand']}
  • fromkeys

使用给定的键建立新的字典,每个键对应的值默认为None,也可以指定:

>>> {}.fromkeys(('name','age'))
{'age': None, 'name': None}
>>> {}.fromkeys(('name','age'),'unknown')#指定'unknown'
{'age': 'unknown', 'name': 'unknown'}
  • get
    get访问字典中不存在的项时不会出错,并返回None。
>>> people
{'rose': 25, 'jack': 36}
>>> print people.get('a')
None
>>> people.get('rose')
25

还可以自定义默认值,当不存在时返回默认值:

>>> people.get('a',10)
10
  • items和iteritems

items方法将字典的所有项以列表的方式返回:

>>> people.items()
[('rose', 25), ('jack', 36)]

iteritems方法返回一个迭代器对象:

>>> it = people.iteritems()
>>> it
<dictionary-itemiterator object at 0x1baa7e0>
>>> list(it) #将迭代器转换为list
[('rose', 25), ('jack', 36)]
  • pop
    获取给定键的值,并将这项从字典中移除

  • popitem

弹出随机的项(键值对)

  • setdeafult

在不含有给定键的情况下设值,存在给定键则返回对应的值。

>>> d = {}
>>> d.setdefault('name','None')
'None'
>>> d
{'name': 'None'}
>>> d.setdefault('name','N/A')
'None'
  • update
    可以用一个字典项更新另外一个字典:
>>> people
{'rose': 25, 'jack': 36}
>>> x = {'jack':24}
>>> people.update(x)
>>> people
{'rose': 25, 'jack': 24}

x中如果有people中不存在的项,也会更新进去:

>>> people
{'rose': 25, 'jack': 24}
>>> x = {'jack':21,'cherry':20}
>>> people.update(x)
>>> people
{'rose': 25, 'jack': 21, 'cherry': 20}

映射的弹性键查询

有时候为了方便,就算某个键在映射(这里指字典)里不存在,我们也希望能获取一个默认值。此时有两个途径可以实现这个目的,一是通过defaultdict这个类型而不是普通的dict,另一个是自定义dict的子类,在子类中实现__missing__方法。

defaultdict

import sys
import re
import collectionsWORD_RE = re.compile(r'\w+')index = collections.defaultdict(list) #以list构造方法作为default_factory来创建一个defaultdict
with open(sys.argv[1],encoding='utf-8') as fp:for line_no,line in enumerate(fp,1):for match in WORD_RE.finditer(line):#返回索引从1开始的序列,值为文件中的行word = match.group()column_no = match.start() + 1location = (line_no,column_no)index[word] .append(location) #如果index中没有word的记录,那么会返回一个空列表for word in sorted(index,key=str.upper):print(word,index[word])

以当前文件作为参数传入,结果输出如下(部分结果):

append [(16, 26)]
argv [(10, 15)]
as [(10, 41)]
coding [(1, 7)]
collections [(5, 8), (9, 9)]
column_no [(14, 13), (15, 33)]
compile [(7, 14)]
defaultdict [(9, 21)]
encoding [(10, 23)]
enumerate [(11, 25)]
finditer [(12, 30)]
for [(11, 5), (12, 9), (18, 1)]
fp [(10, 44), (11, 35)]
group [(13, 26)]
import [(3, 1), (4, 1), (5, 1)]
in [(11, 22), (12, 19), (18, 10)]
index [(9, 1), (16, 13), (18, 20), (19, 16)]
...

所有这一切背后的功臣其实是魔法方法__missing__,它会在defaultdict遇到找不到的键时调用default_factory

__missing__

虽然dict没有定义这个方法,但是它是知道这个方法的存在的。如果某个类继承了dict,然后提供了__missing__方法,那么在__getitem__找不到键的时候,就会自动调用它。

我们定义一个在查询的时候,将映射类型里面的键转换str的类:

# -*- coding: utf-8 -*
class StrKeyDict0(dict):def __missing__(self, key):if isinstance(key,str): #如果找不到的key本身就是字符串,则抛错raise KeyError(key)return self[str(key)] #否则转换成字符串再查找def get(self, key, default=None):try:return self[key] #把查找用self[key]的形式委托给__getitem__except KeyError:return defaultdef __contains__(self, key):return key in self.keys() or str(key) in self.keys()if __name__ == '__main__':d = StrKeyDict0([('2','two'),('4','four')])print(d['2'])#two#print(d[1]) #KeyError: '1'print(d.get('2'))#twoprint(d.get(1,'N/A'))#N/A

字典的变种

上面我们学习了dictdefaultdict,接下来学习其他的映射类型。

  • collections.OrderedDict 在添加键的时候会保持顺序,因此键的迭代顺序是一致的(类似Java中的LinkedHashMap)。popitem([last=True|False])返回字典里最后|第一个被添加进去的元素。
  • collections.ChainMap 可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止。相当于是一个字典的集合。
  • collections.Counter 给键准备一个整数计数器。每次更新一个键的时候都会增加这个计数器。所以这个类型可以用来给可散列表对象计数。
In [2]: import collections                                                                                   In [3]: ct = collections.Counter('abcdabcdabcard')                                                           In [4]: ct
Out[4]: Counter({'a': 4, 'b': 3, 'c': 3, 'd': 3, 'r': 1})In [5]: ct.update('aaaaaazzz')                                                                               In [6]: ct
Out[6]: Counter({'a': 10, 'b': 3, 'c': 3, 'd': 3, 'r': 1, 'z': 3})In [7]: ct.most_common(2) # 返回出现次数最多的两个键和计数
Out[7]: [('a', 10), ('b', 3)]
  • colllections.UserDict 这个类其实就是把标准 dict 用纯 Python 又实现了一遍,主要是提供给用户来扩展的。

子类化UserDict

我们来改进上面的StrKeyDict0类,使得所有的键都存储为字符串类型。

要注意的是UserDict并不是dict的子类,但它有一个名为datadict实例属性(这里有点体现了组合优于继承)。这样做的好处是,UserDict的子类就能在实现__setitem__时避免不必要的递归,也可以让__contains__里的代码更简洁。

# -*- coding: utf-8 -*
import collectionsclass StrKeyDict(collections.UserDict):def __missing__(self, key):if isinstance(key,str): #如果找不到的key本身就是字符串,则抛错raise KeyError(key)return self[str(key)] #否则转换成字符串再查找def __contains__(self, key):return str(key) in self.data #def __setitem__(self, key, value):self.data[str(key)] = value #该方法会把所有的键都转换成字符串if __name__ == '__main__':d = StrKeyDict([('2','two'),('4','four')])print(d['2'])#two#print(d[1]) #KeyError: '1'print(d.get('2'))#twoprint(d.get(1,'N/A'))#N/A

不可变字典类型

有时候我们需要不可变的字典类型,比如在返回某个字典给用户,但又不想让用户修改该字典。从Python3.3开始,types模块中引入了一个封装类名叫MappingProxyType,如果给该类一个映射,它会返回一个只读的映射视图。虽然是只读的,但是能观察到原映射的修改。

In [1]: from types import MappingProxyType                                                                   In [2]: d = {1:'A'}                                                                                          In [3]: d_proxy = MappingProxyType(d)                                                                        In [4]: d_proxy
Out[4]: mappingproxy({1: 'A'})In [5]: d_proxy[2] = 'x'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-bc17a9a62754> in <module>
----> 1 d_proxy[2] = 'x'TypeError: 'mappingproxy' object does not support item assignmentIn [6]: d[2] = 'B'                                                                                           In [7]: d_proxy
Out[7]: mappingproxy({1: 'A', 2: 'B'})

集合

集合是由可迭代对象构造的,可用于去重。
集合是可变的,但本身只能包含不可变(可散列)的值。

>>> set([0,1,2,3,0,1,2,3,4,5])
set([0, 1, 2, 3, 4, 5])

还可以通过字面量来构造:

In [21]: s = {1}
In [22]: type(s)
Out[22]: set
In [23]: s
Out[23]: {1}
In [24]: s.pop()
Out[24]: 1
In [25]: s
Out[25]: set()

{1,2,3}这种字面量相比set([1,2,3])要更快且更易读。

可以求并集和交集:

>>> a = set([1,2,3])
>>> b = set([2,3,4])
>>> a.union(b)
set([1, 2, 3, 4])
>>> a | b #交集
set([1, 2, 3, 4])
>>> c = a & b #并集
>>> c
set([2, 3])
>>> c.issubset(a)
True
>>> c <= a
True
>>> c.issuperset(a)
False
>>> c >= a
False
>>> a.intersection(b)
set([2, 3])
>>> a & b
set([2, 3])
>>> a.difference(b) # 差集
set([1])
>>> a - b
set([1])

可以看到,python重载了很多运算符可以很方便的操作set集合。

集合是可变的,也是不可变的集合类型frozenset

In [34]: frozenset(range(10))
Out[34]: frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})

集合推导

Python2.7带来了集合推导和字典推导。

In [37]: from unicodedata import name
In [42]: {chr(i) for i in range(32, 256) if 'SIGN' in name(chr(i),'')}   #    新建一个 Latin-1 字符集合,该集合里的每个字符的Unicode 名字里都有“SIGN”这个单词
Out[42]:
{'§', '=', '¢', '#', '¤', '<', '¥', 'μ', '×', '$', '¶', '£', '©',
'°', '+', '÷', '±', '>', '¬', '®', '%'}

集合的操作

上图中列出了可变和不可变集合所拥有的方法的概况,其中不少方法是运算符重载的特殊方法。

在Python3中,key()items()values()方法返回的都是字典视图,它们不可修改同时可以实时反馈字典的变化。

setfrozenset的实现依赖散列表,它们在散列表中只存放键而没有相应的值。(这点和Java的Set实现类似)

Python中的字典与集合相关推荐

  1. python中的字典和集合_Python 字典和集合

    字典的每个键值对用冒号分割,键值对之间用逗号分隔,所有键值对包括在{}中. d = {key1 : value1, key2 : value2 } 键必须是唯一的,值可以不唯一.值可以取任何数据类型, ...

  2. python集合与字典区别_Python中的字典与集合

    今天我们来讲一讲python中的字典与集合 Dictionary:字典 Set:集合 字典的语法:Dictionary字典(键值对) 语法: dictionary = {key:value,key:v ...

  3. 深入探究Python中的字典容器

    字典(dictionary) 我们都曾经使用过语言词典来查找不认识的单词的定义.语言词典针对给定的单词(比如 python)提供一组标准的信息.这种系统将定义和其他信息与实际的单词关联(映射)起来.使 ...

  4. python dict是什么意思,python中的字典是什么

    字典定义 1.字典是存储信息的一种方式. 2.字典以键-值对存储信息,因此字典中的任何一条信息都与至少一条其他信息相连. 3.字典的存储是无序的,因此可能无法按照输入的顺序返回信息. Python中定 ...

  5. 零基础Python完全自学教程17:Python中的字典完全解读

    欢迎你来到站长学堂,学习站长在线出品的在线课程<零基础 Python完全自学教程>今天给大家分享的是第17课< Python中的字典完全解读>.本节课是一个大课,我分了这些知识 ...

  6. 如何来理解Python中的字典数据类型

    大家好,我是Python建设者.今天给大家讲解下Python中的字典数据类型. 一.前言 字典是Python中的数据类型,可让将数据存储在键/值对中. 二.什么是字典理解? 字典理解是创建字典的一种优 ...

  7. python代码大全表解释-python中的字典用法大全的代码

    如下代码是关于python中的字典用法大全的代码. #!/usr/bin/env python # # [SNIPPET_NAME: Dictionaries 101] # [SNIPPET_CATE ...

  8. python字典可以切片吗_7.map(感觉跟python中的字典有点像)数组,切片(make)傻傻分不清楚,多多指点...

    1.映射关系容器为map,其内部使用散列表(hash)实现 2.map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用 3.map[KeyType]Val ...

  9. python中列表字典和字符串的相互转化

    python中列表字典和字符串的相互转化有两种方法: (1)使用str和eval的方法,一个简单的例子如下: data = {'name' : 'ACME','shares' : 100,'price ...

  10. python字典怎么设置_在python中设置字典中的属性

    在python中设置字典中的属性 是否可以在python中从字典创建一个对象,使每个键都是该对象的属性? 像这样的东西: d = { 'name': 'Oscar', 'lastName': 'Rey ...

最新文章

  1. 利用windows优化大师软件卸载一手和清理一招
  2. centos7 nginx+php5.6+mysql安装与配置
  3. java参数传入的是一个类名_Java编程细节——泛型的定义(类、接口、对象)、使用、继承...
  4. java单引号转义_Java基础入门——Java语言基础(上)
  5. mysql视图实验心得_Mysql学习经验总结【3】
  6. python获取系统参数_python 常用系统参数
  7. bracket 教程
  8. 201671010430 司昕劼 实验十四 课程学习总结
  9. puppet连载15:搭建zabbix服务端、客户端
  10. Eclipse配置Tomcat并运行
  11. cocos creator基础-(五)cc.Component使用
  12. 22. Window print() 方法
  13. 处理机调度算法——先来先服务、高优先权、按时间片轮转调度算法,高响应比调度算法
  14. 软考初级程序员---题目(七)
  15. 超市管理系统连接服务器失败,超市管理系统应用解决超市管理难题
  16. matlab怎么训练神经网络,matlab神经网络训练方法
  17. 使用Python横向合并excel文件的实例
  18. English in December
  19. influxdb java api使用_InfluxDB使用HTTP的API查询数据
  20. rtsp流php播放插件,nginx+ffmpeg搭建rtmp转播rtsp流的flash服务器

热门文章

  1. 随手练—— 洛谷-P2945 Sand Castle(贪心)
  2. bugfree 数据库配置 显示No such file or directory
  3. The prefix mvc for element mvc:annotation-driven is not bound 的解决方法
  4. apache开源项目--thrift
  5. Problem 2128 最长子串
  6. #leetcode刷题之路27-移除元素
  7. 32位的PLSQL登录64位的ORA11g有关问题
  8. 我所熟悉的网站负载均衡技术之硬件篇
  9. Flex+BlazeDS+Java项目只能使用localhost访问的问题
  10. [翻译]进化游戏的层次结构 - 用组件来重构你的游戏实体