python:字典

字典即映射

  • 字典包含了一个索引的集合,被称为键 (keys) ,和一个值 (values) 的集合。
    • 一个键对应一个值。这种一一对应的关联被称为键值对 (key-value pair) ,有时也被称为项 (item) 。
    • 字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合。
      • k 的取值一般是字符、数字等,像元组其实也是可以的,基本没有使用场景
      • v 的取值可以是字符、数字、元组、列表、字典等所有类型
    • 通常来说,字典中项的顺序是不可预知的。
    • 字典使用哈希表实现,键(key)必须是可散列的:
      • 如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现 __hash__() 方法。
      • 可散列对象还要有 __eq__()方法,这样才能跟其他键做比较。如果两个可散列对象是相等的,那么它们的散列值一定是一样的
      • 原子不可变数据类型(str、bytes 和数值类型)都是可散列类型,frozenset 也是可散列的,因为根据其定义,frozenset 里只能容纳可散列类型。元组的话,只有当一个元组包含的所有元素都是可散列类型的情况下,它才是可散列的。

方法

构造

#--------------------
## 花括号 {} 表示一个空字典
b = {}  
b = {'one': 1, 'two': 2, 'three': 3}


#--------------------
# dict 函数生成一个不含任何项的新字典
a = dict ()  
d = dict(name='孙悟空',age=18,gender='男') 

# 也可以将一个包含有双值子序列的序列转换为字典
# 双值序列,序列中只有两个值,[1,2] ('a',3) 'ab'
# 子序列,如果序列中的元素也是序列,那么我们就称这个元素为子序列
# [(1,2),(3,5)]
d = dict([('name','孙悟饭'),('age',18)])
# print(d , type(d))
d = dict(name='孙悟空',age=18,gender='男') 
 e = dict({'three': 3, 'one': 1, 'two': 2})
  d = dict([('two', 2), ('one', 1), ('three', 3)])
 c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))


  • copy()
    • 该方法用于对字典进行浅复制
    • 复制以后的对象,和原对象是独立,修改一个不会影响另一个
    • 注意,浅复制会简单复制对象内部的值,如果值也是一个可变对象,这个可变对象不会被复制
d = {'a':1,'b':2,'c':3}
d2 = d.copy()
# d['a'] = 100

d = {'a':{'name':'孙悟空','age':18},'b':2,'c':3}
d2 = d.copy()
d2['a']['name'] = '猪八戒'


print('d = ',d , id(d))
print('d2 = ',d2 , id(d2))

字典推导式

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

字典推导式,也是创建字典的一种途径。他的语法结构:
    用大括号包围,第一部分为所需要提取和赋值的键值对,再就是循环语句,再就是逻辑分支语句(没有可不写)

例子:

d = {i: i*10 for i in range(1,5)}
# {1: 10, 2: 20, 3: 30, 4: 40}

# 键值互换
d = {'name': 'Tom', 'age': 18, 'height': 180}
{v:k for k,v in d.items()}
# {'Tom': 'name', 18: 'age', 180: 'height'}

例子:给定一个字典对象{‘a’: 1, ‘b’: 2, ‘c’: 3},找出其中所有大于 1 的键值对,同时 value 值进行平方运算

# # 未使用字典推导式的写法
dc = {'a': 1, 'b': 2, 'c': 3}
d_old = dict()
for k, v in dc.items():
    if v > 1:
        d_old[k] = v ** 2
print(d_old)

# 使用字典推导式
d_new = {k : v ** 2 for k,v in dc.items() if v > 1 }
print(d_new)

遍历

print (tinydict)          # 输出完整的字典
print (tinydict.keys())   # 输出所有键
print (tinydict.values()) # 输出所有值

#遍历 key
d = {'a': 1, 'b': 2, 'c': 3}
for i in d:
    print(i)
# a
# b
# c



# 遍历 key
for i in d.keys():
    print(i)
# 结果同上

# 遍历值
for i in d.values():
    print(i)
# 1
# 2
# 3

# 遍历键值组成元组
for i in d.items():
    print(i)
# ('a', 1)
# ('b', 2)
# ('c', 0)

# 分别取键值遍历
for k in d:
		print (k, d[ k ])
		
for k,v in d.items():
    print(k, v)
# a 1
# b 2
# c 0

一个字典就是一个键集合与值集合的映射关系。

  • 字典的 keys() 方法返回一个展现键集合的键视图对象。
    • 键视图的一个很少被了解的特性就是它们也支持集合操作,比如集合并、交、差运算。
    • 所以,如果你想对集合的键执行一些普通的集合操作,可以直接使用键视图对象而不用先将它们转换成一个 set。
  • 字典的 items() 方法返回一个包含 (键,值) 对的元素视图对象。
    • 这个对象同样也支持集合操作,并且可以被用来查找两个字典有哪些相同的键值对。
  • 尽管字典的 values()返回一个展现value集合的键视图对象。
    • 但是它并不支持集合操作。某种程度上是因为值视图不能保证所有的值互不相同,这样会导致某些集合操作会出现问题
    • 不过,如果你硬要在值上面执行这些集合操作的话,你可以先将值集合转换成 set,然后再执行集合运算就行了。

遍历顺序

在 Python 3.6 版之前字典不会保留插入顺序,在 CPython 3.6 中插入顺序会被保留,但这在当时被当作是一个实现细节而非确定的语言特性。在 3.7 版本中,dict 对象会保持插入时的顺序这个特性 正式宣布 成为 Python 语言官方规范的一部分。

# Python 3.6字典中的键是无序的。如果要以确定的顺序遍历字典,你可以使用内建方法sorted:
for key in sorted ( d ) :
	 print ( key , d[ key ])

添加/修改元素

  • 字典的每个元素中的数据是可以修改的,只要通过key找到,即可修改
  • 如果在使用 变量名[‘键’] = 数据 时,这个“键”在字典中,不存在,那么就会新增这个元素
# d[key] = value 如果key存在则覆盖,不存在则添加
d['name'] = 'sunwukong' # 修改字典的key-value
d['address'] = '花果山' # 向字典中添加key-value

# setdefault(key[, default]) 可以用来向字典中添加key-value
#   如果key已经存在于字典中,则返回key的值,不会对字典做任何操作
#   如果key不存在,则向字典中添加这个key,并设置value
result = d.setdefault('name','猪八戒')
result = d.setdefault('hello','猪八戒')



# update([other])
# 将其他的字典中的key-value添加到当前字典中
# 如果有重复的key,则后边的会替换到当前的
d = {'a':1,'b':2,'c':3}
d2 = {'d':4,'e':5,'f':6, 'a':7}
d.update(d2)

查找/访问元素

  • 根据k找v
info = {'name':'班长','age':18} 

# 通过[]来获取值时,如果键不存在,会抛出异常 KeyError
print(info['age']) # 获取年龄 
# print(info['sex']) # 获取不存在的key,会发生异常 KeyError


print(info.get('sex')) # 获取不存在的key,获取到空的内容,不会出现异常 
print(info.get('sex''男')) # 获取不存在的key, 可以提供一个默认值。


# 嵌套取值
d = {'a': {'name': 'Tom', 'age':18}, 'b': [4,5,6]}
d['b'][1] # 5
d['a']['age'] # 18

  • 逆序查找:
    • 如果你想通过 v 找到 k 呢?有两个问题:
      • 第一,可能有不止一个的键其映射到值 v。你可能可以找到唯一一个,不然就得用 list 把所有的键包起来。
      • 第二,没有简单的语法可以完成逆向查找 (reverse lookup) ;
    • 你必须搜索。
      • 逆向查找比正向查找慢得多;如果你频繁执行这个操作或是字典很大,程序性能会变差。
      • 下面这个函数接受一个值并返回映射到该值的第一个键: 如果我们到达循环结尾,这意味着字典中不存在 v 这个值,所以我们触发一个异常。
def reverse_lookup (d , v ) :
	for k in d :
		if d [ k ] == v :
			return k
raise LookupError ()  # raise 语句能触发异常
# raise LookupError ('value ␣ does ␣not ␣ appear ␣in␣the ␣ dictionary ')

删除元素

  • del:删除指定的元素
info = {'name':'monitor', 'id':100} 
print('删除前,%s'%info) 
del info['name'] # del 也可以直接删除变量 
print('删除后,%s'%info)


#  del info['z'] z不存在,报错

结果:

清空前,{'name': 'monitor', 'id': 100} 
清空后,{'id': 100}
  • del:删除整个字典
info = {'name':'monitor', 'id':100} 
print('删除前,%s'%info) 
del info # del 也可以直接删除变量 
print('删除后,%s'%info)

结果:

删除前,{'name': 'monitor', 'id': 100} 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
NameError: name 'info' is not defined
  • popitem:
    • 随机删除字典中的一个键值对,一般都会删除最后一个键值对
      • 删除之后,它会将删除的key-value作为返回值返回
      • 返回的是一个元组,元组中有两个元素,第一个元素是删除的key,第二个是删除的value
    • 当使用popitem()删除一个空字典时,会抛出异常 KeyError: ‘popitem(): dictionary is empty’
d.popitem()
result = d.popitem()
  • pop(key[, default])
    • 根据key删除字典中的key-value
      • 会将被删除的value返回!
      • 如果删除不存在的key,会抛出异常
      • 如果指定了默认值,再删除不存在的key时,不会报错,而是直接返回默认值
result = d.pop('d')
result = d.pop('z','这是默认值')
  • clear:清空整个字典
info = {'name':'monitor', 'id':100} 
print('清空前,%s'%info) 
info.clear() 
print('清空后,%s'%info)

结果:

清空前,{'name': 'monitor', 'id': 100} 
清空后,{}

应用

获取最大或者最小的key…


prices = { 'ACME': 45.23,
           'AAPL': 612.78,
           'IBM': 205.55,
           'HPQ': 37.20,
           'FB': 10.75
}
  • 获取最大或者最小的key
# 对key操作
print(min(prices))  # AAPL
print(max(prices))  # IBM
  • 获取最大或者最小的value
print(min(prices.values())) #10.75
print(max(prices.values())) #612.78
  • 获取最小值或最大值对应的key
print(min(prices, key=lambda k: prices[k]) ) # Returns 'FB'
print(max(prices, key=lambda k: prices[k]) )# Returns 'AAPL'
  • 获取最大或者最小对应的key和value
# 为了对字典值执行计算操作,通常需要使用 zip() 将字典”反转”为 (值,键) 元组序列。
#		当比较两个元组的时候,值会先进行比较,然后才是键
#		当多个实体拥有相同的值的时候,键会决定返回结果。
min_price = min(zip(prices.values(), prices.keys()))
# min_price is (10.75, 'FB')
max_price = max(zip(prices.values(), prices.keys()))
# max_price is (612.78, 'AAPL')


# 可以使用 zip() 和 sorted() 函数来排列字典数据
prices_sorted = sorted(zip(prices.values(), prices.keys()))
# prices_sorted is [    (10.75, 'FB'), (37.2, 'HPQ'),
#                       (45.23, 'ACME'), (205.55, 'IBM'),
#                       (612.78, 'AAPL')]
  • 执行这些计算的时候,需要注意的是 zip() 函数创建的是一个只能访问一次的迭代器。比如,下面的代码就会产生错误:
prices_and_names = zip(prices.values(), prices.keys())
print(min(prices_and_names)) # OK
print(max(prices_and_names)) # ValueError: max() arg is an empty sequence

怎样在两个字典中寻找相同点(比如相同的键、相同的值等等)

a = {'x' : 1, 'y' : 2, 'z' : 3 }
b = {'w' : 10, 'x' : 11, 'y' : 2 }
  • 可以简单的在两字典的 keys() 或者 items() 方法返回结果上执行集合操作
# Find keys in common
a.keys() & b.keys() # { 'x', 'y' }
# Find keys in a that are not in b
a.keys() - b.keys() # { 'z' }
# Find (key,value) pairs in common
a.items() & b.items() # { ('y', 2) }
  • 这些操作也可以用于修改或者过滤字典元素。比如,假如你想以现有字典构造一个排除几个指定键的新字典。
# Make a new dictionary with certain keys removed
c = {key:a[key] for key in a.keys() - {'z', 'w'}}
# c is {'x': 1, 'y': 2}

做逻辑分支

对于一些逻辑分支功能,字典可以做路由,免去编写if else语句:

route = {True: 'case1', False: 'case2'} # 定义路由
route[7>6] # 'case1' 传入结果为布尔的变量、表达式、函数调用

# 定义计算方法
cal = {'+': lambda x,y: x+y, '*':lambda x,y: x*y}
cal['*'](4,9) # 36 使用

补充

zip函数

  • zip() 函数
    • zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
    • 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
# python3

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 返回一个对象
>>> zipped
<zip object at 0x103abc288>
>>> list(zipped)  # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c))              # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]

>>> a1, a2 = zip(*zip(a,b))          # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]
>>>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

len

len 函数也适用于字典;它返回键值对的个数:

>>> len ( eng2sp )
3

in

in 操作符也适用于字典;它可以用来检验字典中是否存在某个键

>>> 'one ' in eng2sp
True
>>> 'uno ' in eng2sp
False

想要知道字典中是否存在某个值,你可以使用 values 方法,它返回值的集合,然后你可以使用 in 操作符来验证:

>>> vals = eng2sp . values ()
>>> 'uno ' in vals
True

in 操作符对列表和字典采用不同的算法。对于列表,它按顺序依次查找目标,随着列表的增长,搜索时间成正比增长。

对于字典,Python 使用一种叫做哈希表(hashtable) 的算法,这种算法具备一种特性:无论字典中有多少项,in 运算符搜索所需的时间都是一样的。

get

字典类有一个 get 方法,接受一个键和一个默认值作为参数。如果字典中存在该键,则返回对应值;否则返回传入的默认值。

>>> h = histogram ('a')
>>> h
{'a': 1}
>>> h . get ('a', 0)
1
>>> h . get ('b', 0)

sort:排序

  • 现有字典 d= {‘a’:24,‘g’:52,‘i’:12,‘k’:33}请按value值进行排序?
sorted(d.items(),key=lambda x:x[1])

x[0]代表用key进行排序;x[1]代表用value进行排序

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值