【问题标题】:Python: Understanding dictionary view objectsPython:理解字典视图对象
【发布时间】:2018-04-26 15:57:03
【问题描述】:

我一直在尝试理解 Python 3 中 .items().values().keys().viewitems().viewvalues().viewkeys() 类似地返回的内置视图对象。关于该主题还有其他线程,但似乎没有一个(甚至doc)描述了它们在内部是如何工作的。

与 Python 2 中返回的 list 类型的副本相比,这里的主要收获似乎是有效的。经常将字典项与 窗口 进行比较(就像在这个thread 中一样)。

但是那个窗口是什么?为什么它更高效?

我唯一能看到的是视图对象似乎是 set-like 对象,这对于成员资格测试通常更快。但这是唯一的因素吗?

代码示例

>>> example_dict = {'test':'test'}
>>> example_dict.items()
dict_items([('test', 'test')])
>>> type(example_dict.items())
<class 'dict_items'>

所以,我的问题是关于这个dict_items 课程。这在内部是如何运作的?

【问题讨论】:

  • 我确实读过它,但正如我在问题中所说,它使用了我无法在 Python 内部部分理解的窗口类比。
  • @vaultah 我真的不认为这是重复的,因为它没有描述他的 window 代表什么,这正是我要问的。如果你仍然认为是,你能解释一下这个神奇的窗口是什么吗?
  • 票数最高的答案的最后一段说“总而言之,视图只是……字典上的视图(窗口),即使字典发生更改,它也会显示字典的内容”我>。这不能回答你的问题吗?
  • @vaultah:我的回答解释了视图的实际作用。它没有使用“窗口”这个词,因为我认为这个词不能帮助解释视图的实际作用。

标签: python dictionary dictview


【解决方案1】:

字典视图存储对其父字典的引用,并将视图上的操作转换为字典上的相应操作。

迭代 dict 视图比构建列表并对其进行迭代更有效,因为构建列表需要时间和内存,而您不必花费在视图上。旧的方式,Python 会遍历字典的底层存储来构建一个新的列表,然后你会遍历这个列表。迭代字典视图使用一个迭代器直接遍历字典的底层存储,跳过不必要的列表步骤。

Dict 视图还支持高效的包含测试和 setlike 交集/差异/等。操作,因为它们可以对底层 dict 执行直接哈希查找,而不是遍历列表并逐个检查是否相等。

如果想看CPython使用的具体实现,可以看official repository,不过这个实现可能会有变化。它已经多次改变。

【讨论】:

  • 我喜欢这个答案。只是一个小小的语言问题:“......他们将视图上的操作转换为字典上的相应操作。”这表明您可以通过不真实的视图来更改 dict,是吗?
  • 不想脱离上下文,但是 Dict 视图存储对其父 dict 的引用 是什么意思?
  • @scharette:想象一下dict视图的__init__self._secret_inaccessible_attribute = the_dict_youre_making_a_view_of组成。就是这样,但是在 C 中。
  • 这正是我正在寻找的答案。谢谢!
  • @roganjosh:该行指的是迭代器,当您迭代它时,dict 视图会为您提供。这并不是说 dict 视图本身就是一个迭代器。
【解决方案2】:

主要优点之一是视图是动态的:

>>> di={1:'one',2:'two',3:'three'}
>>> view=di.viewitems()
>>> view
dict_items([(1, 'one'), (2, 'two'), (3, 'three')])
>>> di[2]='new two'
>>> view
dict_items([(1, 'one'), (2, 'new two'), (3, 'three')])

因此,如果字典发生更改,您不需要重新生成项目、键或值列表(就像使用 dict.items() 一样)。

将 Python 2 dict.items() 视为 dict 的一种副本——就像复制时的样子。

将 Python 3 dict.items() 或与 dict.viewitems() 等效的 Python 2 视为 dict 现在的最新副本。 (显然与 .viewkeys()、.viewvalues() 相同。)

Python 3.6 documents 有很好的例子说明为什么以及何时使用它。

值视图不是集合式的,因为 dicts 可以有重复的值。键视图是类似集合的,而项目视图对于具有哈希值的 dicts 是类似集合的。

注意:在 Python 3 中,视图用 .keys() .values().items() 替换 Python 2 的视图 有些可能依赖于 dict.keys()dict.values() 作为 dict 先前状态的静态表示可能有惊喜。

【讨论】:

  • "因此,如果字典发生变化,您不需要重新生成项目、键或值列表" - 但标准的习惯用法仍然是每次使用时都创建一个新视图,因为制作一个视图很便宜。很少看到有人费心去存放一个。
  • @user2357112:“很少有人会费心存储一个”如果您查看documentation,示例显示按名称存储视图。你有没有一个例子表明重新生成而不是引用命名对象更好?
  • 在实践中大多数使用 dict 视图是for key, val in d.items()for v in d.values() 之类的东西。我从未见过有人为此费心保存对视图的引用。
  • 抓取一些任意的 Github 存储库(Django、Scikit-learn 和 CPython)并在它们中搜索关键字 items,我看到有人存储 dict 视图的唯一地方是在 dict 视图测试中案例。
  • 但是,如果您不命名视图,则视图的动态特性就不那么明显了。在您使用 for k, v in d.viewitems() 之类的东西迭代视图的同时,dict 很少会发生变化。你能举个例子吗?
猜你喜欢
  • 2015-10-23
  • 2013-01-08
  • 1970-01-01
  • 2022-11-22
  • 2012-02-15
  • 1970-01-01
  • 2019-07-14
  • 1970-01-01
相关资源
最近更新 更多