dict.items()
と dict.iteritems()
の間に適用可能な違いはありますか?
Pythonのドキュメントから:
dict.items()
:辞書の(キー、値)ペアのリストの コピー を返します。
dict.iteritems()
:辞書の(キー、値)ペアに対して イテレータ を返します。
以下のコードを実行すると、それぞれが同じオブジェクトへの参照を返すようです。私が見逃している微妙な違いはありますか?
#!/usr/bin/python
d={1:'one',2:'two',3:'three'}
print 'd.items():'
for k,v in d.items():
if d[k] is v: print '\tthey are the same object'
else: print '\tthey are different'
print 'd.iteritems():'
for k,v in d.iteritems():
if d[k] is v: print '\tthey are the same object'
else: print '\tthey are different'
出力:
d.items():
they are the same object
they are the same object
they are the same object
d.iteritems():
they are the same object
they are the same object
they are the same object
それは進化の一部です。
もともと、Pythonのitems()
はタプルの本当のリストを作り、それを返しました。それは潜在的に多くの余分なメモリを取る可能性があります。
その後、ジェネレータは一般的な言語に導入され、そのメソッドはiteritems()
という名前のイテレータジェネレータメソッドとして再実装されました。オリジナルは後方互換性のために残っています。
Python 3の変更点の1つは、items()
がイテレータを返すようになり、リストが完全に構築されないことです。 Python 3のiteritems()
はPython 2.7のitems()
のように機能するため、viewitems()
メソッドもなくなりました。
dict.items()
は2タプルのリスト([(key, value), (key, value), ...]
)を返しますが、dict.iteritems()
は2タプルを生成するジェネレータです。前者は最初はより多くのスペースと時間がかかりますが、各要素へのアクセスは高速ですが、2番目は最初はより少ないスペースと時間がかかりますが、各要素の生成にはもう少し時間がかかります。
dict.items()
、dict.keys()
、およびdict.values()
コマンドは、辞書の list の(k, v)
ペア、キー、および値の copy を返します。コピーされたリストが非常に大きい場合、これは大量のメモリを消費する可能性があります。
dict.iteritems()
、dict.iterkeys()
、およびdict.itervalues()
コマンドは、辞書の(k, v)
のペア、キー、および値に対して イテレータ を返します。
コマンドdict.viewitems()
、dict.viewkeys()
およびdict.viewvalues()
は、 ビューオブジェクト を返します。これは、辞書の変更を反映することができます。 (つまり、アイテムにdel
を追加したり、辞書に(k,v)
ペアを追加した場合、ビューオブジェクトは同時に自動的に変更できます。)
$ python2.7
>>> d = {'one':1, 'two':2}
>>> type(d.items())
<type 'list'>
>>> type(d.keys())
<type 'list'>
>>>
>>>
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>
>>> type(d.iterkeys())
<type 'dictionary-keyiterator'>
>>>
>>>
>>> type(d.viewitems())
<type 'dict_items'>
>>> type(d.viewkeys())
<type 'dict_keys'>
Py3.xでは、dict.items()
、dict.keys()
、およびdict.values()
のみが利用可能で、Py2.xのdict.viewitems()
と同じように viewオブジェクト が返されるため、状況はよりクリーンです。
@lvcが指摘したように、 view object は iterator と同じではないので、Py3.xで iterator を返したい場合は、 iter(dictview)
:
$ python3.3
>>> d = {'one':'1', 'two':'2'}
>>> type(d.items())
<class 'dict_items'>
>>>
>>> type(d.keys())
<class 'dict_keys'>
>>>
>>>
>>> ii = iter(d.items())
>>> type(ii)
<class 'dict_itemiterator'>
>>>
>>> ik = iter(d.keys())
>>> type(ik)
<class 'dict_keyiterator'>
あなたは尋ねました:「dict.items()とdict.iteritems()の間に適切な違いはありますか」
これは役に立つかもしれません(Python 2.xの場合):
>>> d={1:'one',2:'two',3:'three'}
>>> type(d.items())
<type 'list'>
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>
d.items()
はキーと値の組のタプルのリストを返し、d.iteritems()
は辞書項目区切り文字を返すことがわかります。
リストとして、d.items()はスライス可能です:
>>> l1=d.items()[0]
>>> l1
(1, 'one') # an unordered value!
しかし__iter__
メソッドはありません。
>>> next(d.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator
イテレータとして、d.iteritems()は not slice-ableです。
>>> i1=d.iteritems()[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'dictionary-itemiterator' object is not subscriptable
しかし__iter__
があります:
>>> next(d.iteritems())
(1, 'one') # an unordered value!
そのため、アイテム自体は同じです。アイテムを配信するコンテナは異なります。 1つはリスト、もう1つはイテレータです(Pythonのバージョンによって異なります)。
そのため、dict.items()とdict.iteritems()の間に適用可能な違いは、リストとイテレータの間に適用可能な違いと同じです。
dict.items()
はタプルのリストを返し、dict.iteritems()
はTupleのイタレータオブジェクトを(key,value)
として返します。タプルは同じですが、コンテナは異なります。
dict.items()
は基本的に全ての辞書をリストにコピーします。次のコードを使用して、dict.items()
とdict.iteritems()
の実行時間を比較してみてください。違いがわかります。
import timeit
d = {i:i*2 for i in xrange(10000000)}
start = timeit.default_timer() #more memory intensive
for key,value in d.items():
tmp = key + value #do something like print
t1 = timeit.default_timer() - start
start = timeit.default_timer()
for key,value in d.iteritems(): #less memory intensive
tmp = key + value
t2 = timeit.default_timer() - start
私のマシンで出力する:
Time with d.items(): 9.04773592949
Time with d.iteritems(): 2.17707300186
これはdictionary.iteritems()
がはるかに効率的であることを明確に示しています。
あなたが持っている場合
dict = {key1:value1, key2:value2, key3:value3,...}
Python 2 では、dict.items()
は各タプルをコピーし、タプルのリストを辞書、つまり[(key1,value1), (key2,value2), ...]
で返します。つまり、辞書全体がタプルを含む新しいリストにコピーされるということです。
dict = {i: i * 2 for i in xrange(10000000)}
# Slow and memory hungry.
for key, value in dict.items():
print(key,":",value)
dict.iteritems()
は辞書アイテムのイテレータを返します。返されるアイテムの値も同じ、つまり(key1,value1), (key2,value2), ...
ですが、これはリストではありません。これは辞書アイテムのイテレータオブジェクトです。つまり、メモリ使用量が少なくなります(50%減)。
d.items() -> list(d.items())
d.iteritems() -> iter(d.items())
タプルは同じです。それぞれのタプルを比較したので、同じ結果になります。
dict = {i: i * 2 for i in xrange(10000000)}
# More memory efficient.
for key, value in dict.iteritems():
print(key,":",value)
Python 3 では、dict.items()
はイテレータオブジェクトを返します。 dict.iteritems()が削除されたため、これ以上問題はありません。
dict.iteritems()
:あなたにイテレータを与えます。ループの外側の他のパターンでイテレータを使用することができます。
student = {"name": "Daniel", "student_id": 2222}
for key,value in student.items():
print(key,value)
('student_id', 2222)
('name', 'Daniel')
for key,value in student.iteritems():
print(key,value)
('student_id', 2222)
('name', 'Daniel')
studentIterator = student.iteritems()
print(studentIterator.next())
('student_id', 2222)
print(studentIterator.next())
('name', 'Daniel')
Python 2と3の両方で動作する辞書の項目ペアを反復する方法が必要な場合は、次のようにしてください。
DICT_ITER_ITEMS = (lambda d: d.iteritems()) if hasattr(dict, 'iteritems') else (lambda d: iter(d.items()))
このように使用してください。
for key, value in DICT_ITER_ITEMS(myDict):
# Do something with 'key' and/or 'value'.
Python3.xではdict.iteritems
がなくなったので、iter(dict.iitems())
を使用して同じ出力とメモリ割り当てを取得します。