dictリテラルとdictコンストラクターの使用に違いはありますか?


204

PyCharmを使用して、私はそれがdictリテラルを変換することを提案していることに気づきました:

d = {
    'one': '1',
    'two': '2',
}

dictのコンストラクタ

d = dict(one='1', two='2')

これらの異なるアプローチは、いくつかの重要な点で異なりますか?

(この質問を書いているときにdict()、数字キーを指定することは不可能に思われることに気づきましたd = {1: 'one', 2: 'two'}が、もちろん、可能でdict(1='one' ...)はありません。他に何かありますか?)


4
dict()キーと値のペアのリストを受け取り、名前付きパラメーターを許可するため、使用している構文だけでなく、あらゆるタイプのdictの作成に使用できます。pyCharmにバグ(youtrack.jetbrains.net/issue/PY-2512)があったことは、特に何が発見されたのか、修正されているため、おそらく何の価値もありません。
Wooble

1
関連:stackoverflow.com/questions/5790860/…(概要:PyCharmの動作が遅く、醜い)
Wooble

1
どうやらCPython 2.7 dict()は遅い(6倍遅い?)。参照:doughellmann.com/2012/11/…いずれにしても、dictと関数呼び出しの間でコードを入力して移動する方が簡単なので、とにかくコンストラクター構文を好み始めています。
David Wheaton 2013年

2
スペースを忘れないでください。2番目の方法を使用して、スペースを含むキーを作成することはできません。ただし、最初の方法は任意の文字列をとることができ、問題になりません。もちろん、Unicodeにも同じことが言えます。
CamilB 2013

2
Python 2では、dict(abc = 123)コンストラクターはバイト文字列キーを持つディクショナリーを生成します'abc'。これは、unicode_literalsディクショナリーキーを使用し、ユニコードであると想定している場合は驚くかもしれませんu'abc'stackoverflow.com/questions/20357210/…を参照してください。
Li-aung Yip

回答:


116

最も明白な違いを指摘されたと思います。それとは別に、

最初のものはルックアップする必要がないのでdict、少し速くなります

二ルックスまでdictlocals()、その後globals()、あなたが呼ばれるローカル定義することで動作を切り替えることができますので、組み込みを見つけdict、私はデバッグするとき、これは離れて多分から良いでしょうどこかを考えることはできませんが、例えばを


4
ローカルと呼ばれるdictが便利な例:stackoverflow.com/a/7880276/313113
bitek

また、dict()を使用すると、最初にdict()への引数のdictが作成され、次に実際のdictインスタンスが作成される2番目のdictが作成されます。ブレースは、1つのステップでdictインスタンスを作成します。
NeilG、

56

リテラルは、一般的なCALL_FUNCTIONではなく最適化されたBUILD_MAPおよびSTORE_MAPオペコードを使用するため、はるかに高速です。

> python2.7 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.958 usec per loop

> python2.7 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.479 usec per loop

> python3.2 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.975 usec per loop

> python3.2 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.409 usec per loop

10
@ネッド:ほとんどの場合、ほとんどの場合それは問題ではありませんが、数百万または数十億のものが作成され、2倍のスピードアップが意味を持つ状況があります。
Mr Fooz

5
@MrFooz:そのような状況があります。マイクロタイミングを行う人々の99.9%はそのような状況にいないことがわかります。
Ned Batchelder

29
@Nedどちらがより速いかを尋ねるスレッドに適切です。
エリオット

11
@Elliot OPはどちらが速いか尋ねませんでした。
トムファーガソン

5
ソース内のdictリテラルから、何百万ものdictまたは数百万のキーを持つ1つのdictを作成している場合、それは間違っています。
jwg 2017

41

Python 3.2でもほとんど同じように見えます。

gnibblerが指摘したように、最初のものはをルックアップする必要がないdictため、少し高速になります。

>>> def literal():
...   d = {'one': 1, 'two': 2}
...
>>> def constructor():
...   d = dict(one='1', two='2')
...
>>> import dis
>>> dis.dis(literal)
  2           0 BUILD_MAP                2
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 ('one')
              9 STORE_MAP
             10 LOAD_CONST               3 (2)
             13 LOAD_CONST               4 ('two')
             16 STORE_MAP
             17 STORE_FAST               0 (d)
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE
>>> dis.dis(constructor)
  2           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('one')
              6 LOAD_CONST               2 ('1')
              9 LOAD_CONST               3 ('two')
             12 LOAD_CONST               4 ('2')
             15 CALL_FUNCTION          512
             18 STORE_FAST               0 (d)
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

いくつかの実装では、これは本当に「ほんの少し」ではないことに注意して、より多くの100倍のように:$ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' "{'a': 1, 'b': 2, 'c': 3}" ....... Mean +- std dev: 1.73 ns +- 0.14 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' '{k:v for k,v in i}' ....... Mean +- std dev: 139 ns +- 10 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' 'dict(i)' ....... Mean +- std dev: 188 ns +- 16 ns
DylanYoung

13

これら2つのアプローチは、Pythonの字句規則が干渉するところを除いて、同じ辞書を生成します。

辞書リテラルはもう少し明らかに辞書であり、どんな種類のキーも作成できますが、キー名を引用符で囲む必要があります。一方、何らかの理由で必要な場合は、キーに変数を使用できます。

a = "hello"
d = {
    a: 'hi'
    }

dict()コンストラクタはあなたのためにそれが取る入力の様々な形態のより多くの柔軟性を提供します。たとえば、ペアのイテレータを指定すると、キーと値のペアとして扱われます。

私はなぜPyCharmが1つの形式を別の形式に変換することを提案するのかわかりません。


2
まあ、私はPyCharmがただ特別に素敵にしようとしていると思います。それがいつも一重引用符で囲まれた文字列を二重引用符に変換することを提案しているように見えるのと同じように-明確な理由はありません。
マリグリー

1
キーが文字列である場合にのみ、キーを引用符で囲む必要があります。これらは、フロートのfrozensetのタプルと同じくらい簡単にできますが、これは少し醜いかもしれません。
Wooble

7

python 3.4 + pycharmとの大きな違いの1つは、キーの数が256を超えると、dict()コンストラクターが「構文エラー」メッセージを生成することです。

私は現在、dictリテラルを使用することを好みます。


3
Python 3.4だけではありません。これは、CPython <3.7が呼び出し可能オブジェクトに渡される最大255個のリテラル引数を持つためです。(stackoverflow.com/a/8932175/2718295
cowbert

6

Python 2.7チュートリアルから:

中括弧のペアは空の辞書を作成します:{}。中括弧内にキーと値のペアのコンマ区切りのリストを配置すると、最初のキーと値のペアが辞書に追加されます。これは、出力に辞書が書き込まれる方法でもあります。

tel = {'jack': 4098, 'sape': 4139}
data = {k:v for k,v in zip(xrange(10), xrange(10,20))}

その間:

dict()コンストラクタは、タプルとして保存されたキーと値のペアのリストから直接辞書を構築します。ペアがパターンを形成する場合、リスト内包表記はキー値リストをコンパクトに指定できます。

tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
data = dict((k,v) for k,v in zip(xrange(10), xrange(10,20)))

キーが単純な文字列の場合、キーワード引数を使用してペアを指定する方が簡単な場合があります。

dict(sape=4139, guido=4127, jack=4098)
>>>  {'sape': 4139, 'jack':4098, 'guido': 4127}

したがって、{}とdict()はどちらも辞書を生成しますが、辞書データの初期化には少し異なる方法を提供します。


3

dictリテラルd = {'one': '1'}は、物事に値を割り当ててdict()コンストラクターに送信するのではなく、定義データよりもはるかに読みやすくなっています。

一方、私は人々がdictリテラルをd = {'one', '1'}誤入力して、最新のpython 2.7以降でセットが作成されるのを見てきました。

これにも関わらず、私は今でもセットリテラルを常に使用することを好んでいます。


のリテラル構文がset存在することをいつも忘れています。順序付けられたディクテーションのリテラル構文があればいいのに...セットよりも頻繁に使用します。
ArtOfWarfare 2016年

2

dict()リテラルは、他のものから貼り付け値をコピーするときに便利です(Pythonではありません)たとえば、環境変数のリスト。あなたがbashファイルを持っているなら、言う

FOO='bar'
CABBAGE='good'

簡単にdict()リテラルに貼り付けてコメントを追加できます。また、反対のことを簡単に実行し、別の何かにコピーすることもできます。一方、{'FOO': 'bar'}構文はpythonとjsonに固有のものです。したがって、jsonを頻繁に使用する場合は{}、二重引用符付きのリテラルを使用することをお勧めします。


2

dict継承クラス、追加のメソッドを持つカスタムdictクラスを作成するためのdictリテラルはありません。このような場合、カスタムdictクラスコンストラクターを使用する必要があります。次に例を示します。

class NestedDict(dict):

    # ... skipped

state_type_map = NestedDict(**{
    'owns': 'Another',
    'uses': 'Another',
})

0

また、演算子に一致するトークンは、コンストラクター構文では使用できません(つまり、ダッシュ化されたキー)。

>>> dict(foo-bar=1)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression

>>> {'foo-bar': 1}
{'foo-bar': 1}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.