介绍

我们知道列表是存放数据的容器,需要时我们通过索引(下标)取出数据元素。但是这种取值方式显得不那么友好,我们需要记住数据在列表中的位置才能顺利取值。这种情况下,python给我们提供了另一种基本数据类型,方便我们取值,它就是字典(dict)

字典是由多个 键值对 组成,键(key)是数据的别称,值(value)才是我们需要的数据。此时,我们取数据不需要记住数据存放的顺序,直接报数据的别名就可以取出需要的数据。这种取值方式更加简洁、人性化。

定义字典

# 方式一:
# user = {"键名1": "值名1", "键名2": "值名2", ......}

>>> {"name": "jack", "age": 18}
{'name': 'jack', 'age': 18}

>>> d = {}		# 定义空字典
>>> d
{}

# 方式二:
# user = dict(one=1, two=2)
>>> dict(name='jack',age=18)
{'name': 'jack', 'age': 18}

# 方式三:
info=[
     ['name','egon'],
     ('age',18),
     ['gender','male']
]
res=dict(info) 
# 循环本质:
d={}
for k,v in info: # k,v=['name','egon'],
     d[k]=v
 print(d)

# 方式四:快速初始化一个字典
keys=['name','age','gender']
d={}.fromkeys(keys,None) 

# fromkeys本质循环赋值, 注意如果此时None换为[],字是浅拷贝,导致的结果是每个key对应的value都是一块形同的内存地址
d={}
for k in keys:
     d[k]=None

补充

  • 字典的键必须是不可变数据类型,如int,str, tuple等,并且当tuple包含可变数据类型时也不可以做键;
  • 字典的值可以是任意数据类型。
  • 字典的键是唯一的,一个字典中,键不能重复;值允许重复。

字典基本操作

字典不支持索引取值和切片

# 在字典中键值对,不能像字符串和列表那样通过索引取值,因此也不支持切片操作。
# 字典不支持索引
>>> user = {"name": "jack", "age": 18}
>>> user[0]
Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    user[0]
KeyError: 0
# 字典不支持切片
>>> user[0:2]
Traceback (most recent call last):
  File "<pyshell#34>", line 1, in <module>
    user[0:2]
TypeError: unhashable type: 'slice'

字典通过键取值

# 字典取值直接通过键的方式获取,如果键不存在,则报错。
>>> user['name']
'jack'

修改字典的值

# 修改字典的值,也是通过key的方式
>>> user = {"name": "jack", "age": 18}
>>> user['name']='cindy'
>>> user
{'name': 'cindy', 'age': 18}

字典添加键值对

# 往字典中添加新的键值对,很简单
>>> user = {"name": "jack", "age": 18}
>>> user['sex']='male'
>>> user
{'name': 'jack', 'age': 18, 'sex': 'male'}

删除字典的key-value

# 删除字典的键值对也是通过key的方式
>>> user = {"name": "jack", "age": 18, 'sex': 'male'}
>>> del user['sex']
>>> user
{'name': 'jack', 'age': 18}

del 删除字典、len 获取字典的长度

# 字典的长度,即字典中键的个数
>>> user = {"name": "jack", "age": 18, 'sex': 'male'}
>>> len(user)
3
>>> del user
>>> user
Traceback (most recent call last):
  File "<pyshell#46>", line 1, in <module>
    user
NameError: name 'user' is not defined

in、not in 判断key是否在字典中

# 字典的长度,即字典中键的个数
>>> user = {"name": "jack", "age": 18, 'sex': 'male'}
>>> 'name' in user
True

循环遍历字典

# 使用for询函遍历字典,遍历的是字典的key
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> for i in user:
	    print(i, end=',')

	    
name,age,sex,

总结

  • 字典不支持索引和切片;
  • 字典中,获取、修改、删除数据都需要通过键;
  • 字典的长度是键的个数,遍历字典是遍历字典的键。

内置方法

常用内置方法

get(key, default=None) 返回key对应的value,或者default。程序不会报错

# get()方法获取key对应的value值;
# 并且可以指定如果key不存在时的返回值,默认key不存在什么都不返回。
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.get('name')
'jack'
>>> user.get('height')					# key不存在时,返回None
>>> user.get('height', 'height找不到')	  # 指定返回值
'height找不到'

keys()

# python2中 直接返回一个列表,列表中包含字典的所有key
# python3中,返回一个生成器,循环它时逐个返回字典的key

>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> for i in user.keys():
	    print(i, end=',') 
name,age,sex,

values()

# 与keys类似,返回的是包含values的生成器
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> for i in user.values():
	print(i, end=',')
jack,18,male,

items()

# 与keys、values类似同时返回key和value, 返回的是列表,列表的每个元素是由键和值组成的2元祖。
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> for i in user.items():
	print(i, end=',')
('name', 'jack'),('age', 18),('sex', 'male'),


# 可以采用解压赋值的方式直接获取key和value
>>> for k, v in user.items():
	print(k, v, sep=',')
name,jack
age,18
sex,male

pop(key, default) 通过key删除键值对并返回值,key不存在则返回default(无default则报错)

# 使用key删除字典中的键值对,并返回key对应的value。
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.pop('sex')
'male'

# 如果没有使用可选参数default,key不存在时程序会报错。
>>> user.pop('sex')
Traceback (most recent call last):
  File "<pyshell#84>", line 1, in <module>
    user.pop('sex')
KeyError: 'sex'
    
# 为了避免key不存在而报错,使用可选参数default,自定制返回值
>>> user.pop('sex', 'no sex')
'no sex'

其他内置方法

popitem() 随机删除字典一个键值对,并以2元祖的返回键和值。如果字典为空则报错

>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.popitem()
('sex', 'male')
# 这是因为数据少,看不出来随机删除的效果。

clear()

# 删除字典内所有键值对,字典依然还存在。与列表的clear()相同。

>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.clear()
>>> user
{}

copy() 浅拷贝一个新的字典

# 拷贝新字典并返回
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.copy()
{'name': 'jack', 'age': 18, 'sex': 'male'}

# 浅拷贝的概念日后再说

setdefault(key, default) 有key则返回value,无key则新增key-default并返回default

# 与get()功能类似,通过key获取value
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.setdefault('name')
'jack'

# 当key不存在,不提供value,此时添加一个key,value=None
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.setdefault('height')
>>> user
{'name': 'jack', 'age': 18, 'sex': 'male', 'height': None}

# 当key不存在,提供value,此时添加一个key,value=default,并返回default
>>> user = {"name": "jack", "age": 18, 'sex':'male'}
>>> user.setdefault('height', 175)
175
>>> user
{'name': 'jack', 'age': 18, 'sex': 'male', 'height': 175}

# 通过setdefault()无法修改value
>>> user.setdefault('height', 180)
175
>>> user
{'name': 'jack', 'age': 18, 'sex': 'male', 'height': 175}

fromkeys(iterable, value=None) 字典批处理赋值,有去重作用

# fromkeys的作用:批处理定义一个包含多个键,每个键的值相同的字典
>>> names = ['jack', 'cindy', 'sam']
>>> scores = {}
>>> scores.fromkeys(names, 100)
{'jack': 100, 'cindy': 100, 'sam': 100}

# python源码中,fromkeys是被staticmethod 装饰的函数。故dict也可以调用,这样更方便
>>> scores = dict.fromkeys(names, 100)
>>> scores
{'jack': 100, 'cindy': 100, 'sam': 100}

# 注意:利用 fromkeys 可以给列表去重。 list(dict.fromkeys(my_list))
#注意坑:如果参数value是列表或字典等可变数据类型,每个键都指向相同的内存地址,一个值改变所有键对应的值都改变。

update(E, **F) 将其他字典的键值对添加到该字典中,如果键相同则值替换为新的值

update(self, E=None, **F): 
"""
 D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
 If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
 If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
 In either case, this is followed by: for k in F:  D[k] = F[k]
"""


# case1:如果只有F
>>> d = {'a':1, 'b':2}
>>> f = {'a':2, 'c':3}
>>> d.update(f)			# 没有的新增键值对,已有的更新值
>>> d
{'a': 2, 'b': 2, 'c': 3}

# case2:有E(E是字典),F(F是字典)
>>> d = {'a':1, 'b':2}
>>> f = {'a':2, 'c':3}
>>> e = {'d':4, 'e':5}
>>> d.update(e, f)						# 参数不对,报错
Traceback (most recent call last):
  File "<pyshell#207>", line 1, in <module>
    d.update(e, f)
TypeError: update expected at most 1 arguments, got 2
>>> d.update(e, **f)					# 参数正确
>>> d
{'a': 2, 'b': 2, 'd': 4, 'e': 5, 'c': 3}

# case3:有E(E不是字典,E的元素必须是二元组)
>>> d = {'a':1, 'b':2}
>>> e = [(1,2),(3,4)]		# 元素必须是二元组才能有循环 for k, v in E:
>>> d.update(e)
>>> d
{'a': 1, 'b': 2, 1: 2, 3: 4}

练习

练习1: 有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。即: {'k1': 大于66的所有值, 'k2': 小于66的所有值}。

练习2:统计s='hello alex alex say hello sb sb'中每个单词的个数。结果如:{'hello': 2, 'alex': 2, 'say': 1, 'sb': 2}

练习3:三级菜单,要求打印 省市县三级菜单,可随时返回上一级和退出程序。


补充

dict的key是有序的?

python3.5(含)以前是不能保证先添加的键值对先循环打印出来;

python3.6后,对字典的底层存储做了改进,支持先添加的键值对,先循环打印。

点击了解一下1

点击了解一下2


有序字典 OrderedDict

OrderedDict 是python内部collections模块提供的一个类,OrderedDict 继承dict。

OrderedDict 支持键插入的顺序。python3.6以后普通字典已经支持字典key的有序化。但是OrderedDict 依然有它的特殊之处,特定的时候使用方便。

1-创建有序字典

from collections import OrderedDict		# 引入OrderedDict类

order_dict = OrderedDict()				# 实例化order_dict(有序字典对象)
for i in range(5):						# 循环插入键值对
    order_dict[i] = i*10

print(order_dict)	# OrderedDict([(0, 0), (1, 10), (2, 20), (3, 30), (4, 40)])

2-获取有序字典的key

print(order_dict.keys())		# odict_keys([0, 1, 2, 3, 4])
for key in order_dict.keys():	# 0 1 2 3 4 
    print(key, end=' ')

3-获取有序字典的value

print(order_dict.values())			# odict_values([0, 10, 20, 30, 40])
for value in order_dict.values():	# 0 10 20 30 40 
    print(value, end=' ')

4-同时获取key-value

print(order_dict.items())			
for k, v in order_dict.items():
    print((k, v), end=' ')

# output:
# odict_items([(0, 0), (1, 10), (2, 20), (3, 30), (4, 40)])
# (0, 0) (1, 10) (2, 20) (3, 30) (4, 40)

5-pop(key, default)

# 同dict的pop(key, default)方法相同
# 如果key存在则删除key对应的键值对,并返回value
# 如果key不存在,则返回default的值,default没有指定的报错。

6-copy() & clear()

# # 同dict的copy()、clear()方法相同。复制和清空有序字典

7-setdefault(key, default)

# 同dict的setdefault()方法相同
# 如果key不在字典中,插入key-default键值对,并返回default,无default则返回None
# 如果key在字典中,则返回key对应的value值

8-fromkeys(cls, iterable, value=None)

# 同dict的fromkeys方法相同,都是静态方法,类和对象都可以调用
# 将一个可迭代对象的元素当做字典的key,value是初始值
# 记得坑:如果value是一个可变数据类型。修改字典中的任何一个value,则所有的value都相应变化

上述方法具有Dict的对应的方法在使用方式和功能上完全一样。

下面两个方法是OrderedDict的特殊方法。


9-popitem(self, last=True)

# OrderedDict的popitem与dict.popitem()方法不同
# 有序字典的popitem 删删除一个键值对并返回键值对,可以按照后进先出的顺序;也可以按照先进先出的顺序删除

# last=Ture(默认), 后进先出LIFO
for _ in range(5):
    print(order_dict.popitem(), order_dict)
# 输出:
# (4, 40) OrderedDict([(0, 0), (1, 10), (2, 20), (3, 30)])
# (3, 30) OrderedDict([(0, 0), (1, 10), (2, 20)])
# (2, 20) OrderedDict([(0, 0), (1, 10)])
# (1, 10) OrderedDict([(0, 0)])
# (0, 0) OrderedDict()


# last=False, 先进先出FIFO
for _ in range(5):
    print(order_dict.popitem(last=False), order_dict)
# 输出
# (0, 0) OrderedDict([(1, 10), (2, 20), (3, 30), (4, 40)])
# (1, 10) OrderedDict([(2, 20), (3, 30), (4, 40)])
# (2, 20) OrderedDict([(3, 30), (4, 40)])
# (3, 30) OrderedDict([(4, 40)])
# (4, 40) OrderedDict()

10-move_to_end(self, key, last=True)

# move-to_end是OrderedDict的特殊方法
'''Move an existing element to the end (or beginning if last is false).

        Raise KeyError if the element does not exist.
        '''
# 如果key存在, 默认将key-value移到最后一位,也可以移到第一位(last=False)
# 如果key不存在则报错

print('移动前:', order_dict)
order_dict.move_to_end(2)			# 将(2, 20)移到尾部
print('移到尾部:', order_dict)
order_dict.move_to_end(3, last=False)	# 将(3,30)移到头部
print('移到头部:', order_dict)

# 输出:
移动前: OrderedDict([(0, 0), (1, 10), (2, 20), (3, 30), (4, 40)])
移到尾部: OrderedDict([(0, 0), (1, 10), (3, 30), (4, 40), (2, 20)])
移到头部: OrderedDict([(3, 30), (0, 0), (1, 10), (4, 40), (2, 20)])