哈喽大家好,我是咸鱼

我们知道字典是 Python 中最重要且最有用的内置数据结构之一,它们无处不在,是语言本身的基本组成部分

我们可以使用字典来解决许多编程问题,那么今天我们就来看看如何在 Python 中遍历字典

全文内容:https://realpython.com/iterate-through-dictionary-python/

ps:文中提到的 Python 指的是 CPython 实现;

译文如下:

字典是 Python 的基石。这门语言的很多方面都是围绕着字典构建的

模块、类、对象、globals()locals() 都是字典与 Python 实现紧密联系的例子

以下是 Python 官方文档定义字典的方式:

An associative array, where arbitrary keys are mapped to values. The keys can be any object with __hash__() and __eq__() methods

需要注意的是:

  • 字典将键映射到值,并将它们存储在数组或集合中。键值对通常称为 items
  • 字典键必须是可哈希类型,这意味着它们必须具有在键的生命周期内永远不会更改的哈希值

与序列不同,序列是支持使用整数索引进行元素访问的可迭代对象,字典按键编制索引。这意味着我们可以使用关联的键而不是整数索引来访问存储在字典中的值

字典中的键很像 set ,它是可哈希和唯一对象的集合。由于键需要可哈希处理,因此不能将可变对象用作字典键(即键不能是可变数据类型)

另一方面,字典值可以是任何 Python 类型,无论它们是否可哈希。从字面上看,对值没有任何限制。我们可以使用任何数据类型作为 Python 字典中的值

在Python 3.6之前,字典是无序的数据结构。这意味着 item 的顺序通常与插入顺序不匹配

  1. >>> # Python 3.5
  2. >>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
  3. >>> likes
  4. {'color': 'blue', 'pet': 'dog', 'fruit': 'apple'}

可以看到,生成的词典中 item 的顺序与最初插入 item 的顺序不匹配

在 Python 3.6 及更高版本中,字典的键和值保持与将它们插入底层字典的顺序相同。即从3.6 开始,字典变成了紧凑有序的数据结构

  1. >>> # Python 3.6
  2. >>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
  3. >>> likes
  4. {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}

保持 item 有序是一个非常有用的功能。但是,如果使用的代码支持较旧的 Python 版本,则不能依赖此功能,因为它可能生成 bug,对于较新的版本,依赖该特性是完全安全的

字典的另一个重要特征是它们是可变的数据类型。这意味着我们可以根据需要就地添加、删除和更新其项目

值得注意的是,这种可变性也意味着不能将字典用作另一个字典中的键

如何在 python 中遍历字典

Python 开发人员经常会遇到这样的情况:在对其键值对执行某些操作时,需要遍历现有字典

因此,了解 Python 中字典迭代的不同方法非常重要。保持 item 有序是一个非常有用的功能

  • 直接遍历字典

Python 的字典有一些特殊的方法,Python 在内部使用它们来执行一些操作

这两个方法的命名约定是,在方法名的开头和末尾分别添加两个下划线

可以使用内置 dir() 函数获取任何 Python 对象提供的方法和属性的列表。如果使用空字典作为参数运行 dir() ,则将获得 dict 该类的所有方法和属性

  1. >>> dir({})
  2. ['__class__', '__contains__', '__delattr__', ... , '__iter__', ...]

可以看到'__iter__' 这个属性,这是 Python 在需要容器数据类型的迭代器时自动调用的方法

该方法应该返回一个新的迭代器对象,该对象允许我们遍历底层容器类型中的所有项

对于 Python 字典,默认情况下允许 .__iter__() 直接迭代键。如果你直接在 for 循环中使用字典,Python 将自动调用 .__iter__() 属性,你会得到一个遍历其键的迭代器

  1. >>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
  2. >>> for key in likes:
  3. ... print(key)
  4. ...
  5. color
  6. fruit
  7. pet

Python 足够聪明,知道 likes 是一个字典,并且它实现了.__iter__()。在这个例子中,Python自动调用.__iter__(),这允许迭代 likes 字典的键

这是在 Python 中遍历字典的主要方法——你只需要把字典直接放进一个 for 循环中

如果将此方法与 [key] 运算符一起使用,则可以在循环访问键时访问字典的值

  1. >>> for key in likes:
  2. ... print(key, "->", likes[key])
  3. ...
  4. color -> blue
  5. fruit -> apple
  6. pet -> dog

在本例中,同时使用 key likes[key] 来分别访问目标字典的键和值

尽管在 Python 中直接遍历字典非常简单,但字典提供了更方便、更明确的工具来获得相同的结果

.items() 该方法就是这种情况,它定义了一种快速迭代字典的 item 或键值对的方法

  • .items()方法遍历字典 item

使用字典时,同时循环访问键和值可能是一个常见要求。 .items() 方法返回一个视图对象,其中包含字典的项作为键值元组:

  1. >>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
  2. >>> likes.items()
  3. dict_items([('color', 'blue'), ('fruit', 'apple'), ('pet', 'dog')])

字典视图对象提供字典项的动态视图。在这里,动态意味着当字典更改时,视图会反映这些更改

视图是可迭代的,因此我们可以使用调用 .items() 生成的视图对象循环访问字典中的项,如以下示例所示:

  1. >>> for item in likes.items():
  2. ... print(item)
  3. ...
  4. ('color', 'blue')
  5. ('fruit', 'apple')
  6. ('pet', 'dog')

在此示例中, 返回一个视图对象,该对象一次生成一个键值对, .items() 并允许我们循环访问它们

如果仔细观察产生的各个项目 .items() ,那么会注意到它们是 tuple 对象:

  1. >>> for item in likes.items():
  2. ... print(item)
  3. ... print(type(item))
  4. ...
  5. ('color', 'blue')
  6. <class 'tuple'>
  7. ('fruit', 'apple')
  8. <class 'tuple'>
  9. ('pet', 'dog')

可以看到所有的 item 都是元组。一旦知道了这一点,就可以使用元组解包来并行地遍历键和值

要通过键和值实现并行迭代,只需将每个 item 的元素解压缩为两个不同的变量:一个用于键,另一个用于值

  1. >>> for key, value in likes.items():
  2. ... print(key, "->", value)
  3. ...
  4. color -> blue
  5. fruit -> apple
  6. pet -> dog

for 循环头中的 key 和 value 变量执行解包操作。每次循环运行时,key获得对当前键的引用,value获得对值的引用

这样,我们就可以更好地控制字典内容。因此,我们将能够以可读和 python 的方式分别处理键和值

  • .keys() 方法遍历字典的键

Python 字典提供了第二种遍历其键的方法。除了在循环中直接使用目标字典外,还可以使用.keys()方法

这个方法返回一个只包含字典键的视图对象

  1. >>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
  2. >>> likes.keys()
  3. dict_keys(['color', 'fruit', 'pet'])

该方法 .keys() 返回一个对象,该对象提供 likes 键的动态视图。可以使用此视图对象循环访问字典键

  1. >>> for key in likes.keys():
  2. ... print(key)
  3. ...
  4. color
  5. fruit
  6. pet

当您在 likes上调用 .keys() 时,将获得键的视图。Python 知道视图对象是可迭代的,所以它开始循环

为什么要使用 .keys() 而不是直接遍历字典。简单来说,显式地使用 .keys()可以让你更好地表达只遍历键的意图

  • .values() 方法遍历字典值

在遍历字典时面临的另一个常见需求是只遍历值。方法是使用 .values() 方法,它会返回一个包含底层字典中的值的视图

  1. >>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
  2. >>> likes.values()
  3. dict_values(['blue', 'apple', 'dog'])

上面的代码返回一个视图对象, .values() 返回一个视图对象。

与其他视图对象一样,的结果 .values() 也是可迭代的,因此可以在循环中使用它

  1. >>> for value in likes.values():
  2. ... print(value)
  3. ...
  4. blue
  5. apple
  6. dog

使用 .values() ,只能访问目标字典的值

  • 在迭代期间更改值

有时,在 Python 中迭代字典时需要更改字典中的值

在下面的例子中,你在一个字典中更新了一堆产品的价格:

  1. >>> fruits = {"apple": 0.40, "orange": 0.35, "banana": 0.25}
  2. >>> for fruit, price in fruits.items():
  3. ... fruits[fruit] = round(price * 0.9, 2)
  4. ...
  5. >>> fruits
  6. {'apple': 0.36, 'orange': 0.32, 'banana': 0.23}

在上面的例子中需要注意的是:为了更新值,我们使用了原始的字典,而不是像price = round(price * 0.9, 2)这样直接更新当前的价格

如果像price = round(price * 0.9, 2)这样,重新分配水果或价格并没有反映在原来的字典中

就会导致丢失对字典的引用,这样并没有实现更改字典中的任何内容

  • 在迭代期间安全地删除 item

由于 Python 字典是可变的,我们可以根据需要从中删除现有的 item

在下面的示例中,我们根据项的特定值选择性地删除项

注意,为了在遍历字典时安全地缩小字典,我们需要使用一个副本

  1. >>> fruits = {"apple": 0.40, "orange": 0.35, "banana": 0.25}
  2. >>> for fruit in fruits.copy():
  3. ... if fruits[fruit] >= 0.30:
  4. ... del fruits[fruit]
  5. ...
  6. >>> fruits
  7. {'banana': 0.25}

在本例中,使用 .copy() 创建目标字典fruits的浅副本。然后循环遍历副本,同时从原始字典中删除项,在本例中,使用 del 语句删除字典项

但是也可以使用 .pop() 将目标键作为参数

如果在尝试删除循环中的 item 时不使用目标词典的副本,则会收到错误

  1. >>> fruits = {"apple": 0.40, "orange": 0.35, "banana": 0.25}
  2. >>> for fruit in fruits:
  3. ... if fruits[fruit] >= 0.30:
  4. ... del fruits[fruit]
  5. ...
  6. Traceback (most recent call last):
  7. File "<input>", line 1, in <module>
  8. for fruit in fruits:
  9. RuntimeError: dictionary changed size during iteration

当你试图在迭代过程中从字典中删除一个 item 时,Python 会引发 RuntimeError

由于原始字典的大小发生了变化,因此如何继续迭代是不明确的。因此,要避免这个问题,请始终在迭代中使用字典的副本

遍历期间对字典的操作

  • 根据值来过滤 item

有时候我们希望在原字典的前提下创建一个只包含满足特定条件的新字典

我们可以在遍历原字典的时候加上条件判断

  1. >>> numbers = {"one": 1, "two": 2, "three": 3, "four": 4}
  2. >>> small_numbers = {}
  3. >>> for key, value in numbers.items():
  4. ... if value <= 2:
  5. ... small_numbers[key] = value
  6. ...
  7. >>> small_numbers
  8. {'one': 1, 'two': 2}

在此示例中,筛选值小于的项目 2 ,并将它们添加到 small_numbers 字典中

还有另一种技术可以用来从字典中过滤 item。因为键的视图对象类似于 Python 集合对象

因此,它们支持集合操作,例如并集、交集和差分。可以利用这种类似集合的行为从字典中过滤某些键

  1. >>> fruits = {"apple": 0.40, "orange": 0.35, "banana": 0.25}
  2. >>> fruits.keys() - {"orange"}
  3. {'apple', 'banana'}

还可以更简洁

  1. >>> numbers = {"one": 1, "two": 2, "three": 3, "four": 4}
  2. >>> {key: value for key, value in numbers.items() if value <= 2}
  3. {'one': 1, 'two': 2}

或者通过计算字典的键与一组不需要的键之间的差分而获得的键集构建一个新词典

  1. >>> non_citrus = {}
  2. >>> for key in fruits.keys() - {"orange"}:
  3. ... non_citrus[key] = fruits[key]
  4. ...
  5. >>> non_citrus
  6. {'apple': 0.4, 'banana': 0.25}
  • 算术运算

在遍历字典时,我们可以对字典的值进行计算

  1. >>> incomes = {"apple": 5600.00, "orange": 3500.00, "banana": 5000.00}
  2. >>> total_income = 0.00
  3. >>> for income in incomes.values():
  4. ... total_income += income
  5. ...
  6. >>> total_income
  7. 14100.0

或者使用内置的 sum() 函数。把字典中的值作为参数直接传递给 sum() 来求和

  1. >>> incomes = {"apple": 5600.00, "orange": 3500.00, "banana": 5000.00}
  2. >>> sum(incomes.values())
  3. 14100.0
  • 键值交换

我们可以在遍历的时候交换字典的键和值

  1. >>> numbers = {"one": 1, "two": 2, "three": 3, "four": 4}
  2. >>> swapped = {}
  3. >>> for key, value in numbers.items():
  4. ... swapped[value] = key
  5. ...
  6. >>> swapped
  7. {1: 'one', 2: 'two', 3: 'three', 4: 'four'}

更简洁的写法

  1. >>> numbers = {"one": 1, "two": 2, "three": 3, "four": 4}
  2. >>> {value: key for key, value in numbers.items()}
  3. {1: 'one', 2: 'two', 3: 'three', 4: 'four'}

需要注意的是,原始字典值中的数据必须是可哈希数据类型

我们还可以将内置 zip() 函数与 dict() 构造函数一起使用

  1. >>> dict(zip(numbers.values(), numbers.keys()))
  2. {1: 'one', 2: 'two', 3: 'three', 4: 'four'}

上面的示例中,通过 zip() 生成值键对的元组,然后,使用生成的元组作为参数并 dict() 构建所需的字典

字典推导式

与列表推导式不同,字典推导式需要一个映射到值的键

  1. >>> categories = ["color", "fruit", "pet"]
  2. >>> objects = ["blue", "apple", "dog"]
  3. >>> likes = {key: value for key, value in zip(categories, objects)}
  4. >>> likes
  5. {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}

上面的对象中, zip() 接收两个可迭代对象( categoriesobjects )生成了一个 tuple 对象,然后被解压缩到 keyvalue 中,最终用于创建新的所需字典

更简洁的方法如下:

  1. >>> categories = ["color", "fruit", "pet"]
  2. >>> objects = ["blue", "apple", "dog"]
  3. >>> dict(zip(categories, objects))
  4. {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}

zip() 函数从原始列表生成键值对,而 dict() 构造函数负责创建新字典

Python 遍历字典的若干方法的更多相关文章

  1. Python遍历字典

    1.遍历key值 1 >>> d = {'Python':'astonishing', 'C++':'complicated', 'Java':'versatile'} 2 > ...

  2. python遍历字典元素

    a={'a':{'b':{'c':{'d':'e'}},'f':'g'},'h':'i'} def show(myMap): for str in myMap.keys(): secondDict=m ...

  3. python 遍历字典中的键和值

    #遍历字典中的所有键和值 zd1={"姓名":"张三","年龄":20,"性别":"女"} zd2= ...

  4. Python遍历字典dict的几种方法

    #!/usr/bin/python dict={"a":"apple","b":"banana","o&quo ...

  5. Python day6_dictionary字典的常见方法1_笔记(基本类型结束)

    # 字典的简述 # 1.字典不能做字典的key,列表也不能作为列表的key info={ 'k1':'v1', 'k2':'v2' } print(info) #2.通过键获取值 print(info ...

  6. python关于字典的使用方法

    #-*- coding:utf-8 -*-#Author:gxli#定义字典id_db={ 233333199211222342:{ 'name':'xiaoa', 'age':23, 'addr': ...

  7. python中字典常用的方法

    #定义一个空字典: a={ } 定义一个字典: d={'age':18} #增加一个元素: d['age']=20   d[k]=v d.setdefault('age',18)    d.setde ...

  8. python遍历删除列表的方法

    for item in list(somelist): somelist.remove(item)

  9. python中字典dict pop方法

    首先引用下pythondoc pop(key[, default]) If key is in the dictionary, remove it and return its value, else ...

  10. python 遍历字典

    dict={"a":"apple","b":"banana","o":"orange&qu ...

随机推荐

  1. 批处理bat and 汇编小技巧

    来自远古时期的汇编软件MASM是没有像现在一样的exe程序的(汇编萌新的认知),所以为了快捷,写一些bat来方便操作.([表情包]奇怪的知识增加了)哈哈哈 我现在是MASM的路径是D:\Masm64\ ...

  2. css预编译sass和stylus简单使用

    目前css 流行的三大预编译有stylus.less . sass 说白了这些东西就是为了提高编码效率,更好的规整和简化 css代码的,相信大家less 就不用多说了用得都比较多了,在这里简单记录下s ...

  3. 代码随想录算法训练营Day21 二叉树

    代码随想录算法训练营 代码随想录算法训练营Day21 二叉树| 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先 530.二叉搜索树的最小绝对差 题目链接:5 ...

  4. SPI通信协议

    1. SPI 通信协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设 备接口,是一种高速全双工的通信总线.它被广泛地使用在 A ...

  5. 如何获取 C#程序 内核态线程栈

    一:背景 1. 讲故事 在这么多的案例分析中,往往会发现一些案例是卡死在线程的内核态栈上,但拿过来的dump都是用户态模式下,所以无法看到内核态栈,这就比较麻烦,需要让朋友通过其他方式生成一个蓝屏的d ...

  6. flutter系列之:做一个会飞的菜单

    目录 简介 定义一个菜单项目 让menu动起来 添加菜单内部的动画 总结 简介 flutter中自带了drawer组件,可以实现通用的菜单功能,那么有没有一种可能,我们可以通过自定义动画来实现一个别样 ...

  7. JavaWeb编程面试题——导航

    引言 面试题==知识点,这里所记录的面试题并不针对于面试者,而是将这些面试题作为技能知识点来看待.不以刷题进大厂为目的,而是以学习为目的.这里的知识点会持续更新,目录也会随时进行调整. 关注公众号:编 ...

  8. Java中打印对象输出的字符串到底是什么?

    前言 我们在进行 Java 编程时,经常要打印对象,有的是查看是否拿到了该对象,有的是查看该对象中的数据.打印输出的却是一知半解的字符串,那么这个字符串是怎么来的?代表什么?我们如何打印出对象中的数据 ...

  9. OpenAI发布ChatGPT函数调用和API更新

    2023年6月13日,OpenAI针对开发者调用的API做了重大更新,包括更易操控的 API模型.函数调用功能.更长的上下文和更低的价格. 在今年早些时候发布gpt-3.5-turbo,gpt-4在短 ...

  10. Ryu控制器教程

    RYU不要使用apt的方法安装,这样的安装是不完整的, 并且相关文件不易查找. 1.下载ryu源码 cd cd Desktop git clone https://gitee.com/lpm-123/ ...