27

Python 2.7では、ディクショナリにはiterkeysメソッドとメソッドの両方viewkeys(および値とアイテムの同様のペア)があり、ディクショナリのキーを遅延反復する2つの異なる方法を提供します。このviewkeysメソッドは、の主要な機能を提供し、iterkeys実質的にはとiter(d.viewkeys())同等d.iterkeys()です。さらに、返されるオブジェクトにviewkeysは、便利なセットのような機能があります。viewkeysしたがって、を支持する強い理由がありますiterkeys

他の方向はどうですか?以前のバージョンのPythonとの互換性とは別に、よりiterkeys好ましい方法はありviewkeysますか?いつも使うだけで何かが失われるのでしょうviewkeysか?

4

4 に答える 4

21

ディクショナリビューはディクショナリと同じように更新されますが、イテレータは必ずしもこれを行うとは限りません。

つまり、ビューを操作し、辞書を変更してから、ビューを再度操作すると、ビューは辞書の新しい状態を反映するように変更されます。

これらは、ディクショナリのエントリに関する動的なビューを提供します。つまり、ディクショナリが変更されると、ビューはこれらの変更を反映します。 ソース

例:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> b = test.viewkeys()
>>> del test[1]
>>> test[5] = 6
>>> list(a)
[3, 5]
>>> b
dict_keys([3, 5])

サイズに変更が加えられると、例外がスローされます。

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> b = test.viewkeys()
>>> test[5] = 6
>>> list(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> b
dict_keys([1, 3, 5])

また、キーイテレーターを繰り返すことができるのは1回だけであることに注意してください。

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> list(a)
[1, 3]
>>> list(a)
[]
>>> b = test.viewkeys()
>>> b
dict_keys([1, 3])
>>> b
dict_keys([1, 3])
于 2012-04-17T10:57:21.583 に答える
15

機能面では、ご覧のとおり、ビューの方が優れています。互換性に関しては、それらはさらに悪いです。

64ビットUbuntuマシン上のPython2.7.2から取得したいくつかのパフォーマンスメトリック:

>>> from timeit import timeit

空の辞書の処理:

>>> emptydict = {}
>>> timeit(lambda: emptydict.viewkeys())
0.24384498596191406
>>> timeit(lambda: list(emptydict.viewkeys()))
0.4636681079864502
>>> timeit(lambda: emptydict.iterkeys())
0.23939013481140137
>>> timeit(lambda: list(emptydict.iterkeys()))
1.0098130702972412

ビューの構築は少しコストがかかりますが、ビューの消費はイテレータよりも大幅に高速です(2倍を少し超える速度)。

千要素辞書の取り扱い:

>>> fulldict = {i: i for i in xrange(1000)}
>>> timeit(lambda: fulldict.viewkeys())
0.24295306205749512
>>> timeit(lambda: list(fulldict.viewkeys()))
13.447425842285156
>>> timeit(lambda: fulldict.iterkeys())
0.23759889602661133
>>> timeit(lambda: list(fulldict.iterkeys()))
15.45390510559082

あまり目立たないが、同じ結果。ビューの作成はごくわずかに費用がかかりますが、それを消費する方が間違いなく高速です(15%高速)。

list(dict.viewkeys())およびとの公正な比較のためにlist(dict.iterkeys())dict.keys()は明らかに高速です。

>>> timeit(lambda: emptydict.keys())
0.2385849952697754
>>> timeit(lambda: fulldict.keys())
7.842105150222778

要約:これはトレードオフです。より優れた機能(めったに使用しない)とパフォーマンス(これは、心配するほど重要になることはめったにありません。このようなパフォーマンスの問題を気にしている場合は、おそらくすでにnumpy/scipyを操作する必要がある領域にいます。 )対より良い互換性と筋肉のメモリ使用量。

個人的には、2.7のみの機能にすでに依存していない限り、またはランタイム環境を完全に制御しているのでない限り、Python2コードの辞書ビューは避けます。このような場合でも、指iterではなく入力したいviewので、'em!

于 2012-04-17T11:20:11.260 に答える
12

いいえ、どちらにもメリットがないのと同じように、iterkeysオーバーにメリットはありません。下位互換性のためだけにあります。実際、Python 3では、まだ存在している唯一の動作であり、名前が変更されています。このメソッドは、実際にはPython3の動作のバックポートです。viewkeyskeysiterkeysviewkeyskeysviewkeys

于 2012-04-17T10:59:52.090 に答える
9

名前(およびドキュメント)が示すようにviewkeys()viewvalues()およびviewitems()メソッドはディクショナリ内の現在の要素のビューを返します。つまり、ディクショナリが変更されると、ビューも変更されます。ビュー 怠惰です。一般的な場合、キービューはセットのようであり、アイテムビューは、値がハッシュ可能である場合にのみセットのようになります。

どのような場合に標準的な方法を使用するのが良いでしょうかkeys()values()そしてitems()?あなたは非常に重要なものについて言及しました:後方互換性。また、すべてのキー、値、またはアイテムの単純なリスト(セットのようなものではなく、イテレーターではない)が必要な場合、元のディクショナリを変更せずに返されたリストを変更する必要がある場合、およびディクショナリに対する後の変更に関係なく、ある時点でのディクショナリのキー、値、またはアイテム。

そして、どうですかiterkeys()itervalues()そしてiteritems()?これらは、辞書の内容のワンショット、一定スペース、遅延イテレータスナップショットが必要な場合に適した代替手段であり、(を介して)反復中に辞書が変更されたかどうかをRuntimeError示します。また、下位互換性のために非常に重要です。 。

于 2012-04-17T11:10:02.780 に答える