使用dict文字和dict构造函数之间有区别吗?


204

我注意到使用PyCharm可以转换字典文字

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中有一个bug(youtrack.jetbrains.net/issue/PY-2512)可能也毫无价值,特别是因为您所发现的问题已得到修复。
Wooble

1
相关:stackoverflow.com/questions/5790860/…(摘要:PyCharm的行为较慢且较丑)
Wooble

1
显然,CPython 2.7 dict()较慢(慢6倍?)。请参阅:oughellmann.com/2012/11/…在任何情况下,无论如何我都开始偏爱构造函数语法,因为我发现在dict和函数调用之间键入和移动代码更容易。
大卫•惠顿

2
不要忘记空格:您无法使用第二种方法创建包含空格的键。但是,第一种方法可以采用任何字符串,这无关紧要。当然,这同样适用于Unicode。
CamilB

2
在Python 2中,dict(abc = 123)构造函数生成带有字节字符串键的字典,'abc'如果您正在使用unicode_literals并且期望字典键为unicode ,这可能会令人惊讶u'abc'。参见stackoverflow.com/questions/20357210/…
叶李昂

Answers:


116

我认为您已经指出了最明显的区别。除此之外,

第一个不需要查找dict,这会使它更快一点

第二查找dictlocals(),然后globals()和出土文物内置的,所以你可以通过定义一个本地被叫交换机的行为dict,例如,虽然我想不出任何地方,这将是一个好主意,除了也许当调试


4
一个本地的dict可能有用的示例:stackoverflow.com/a/7880276/313113
bitek 2014年

我相信也使用dict()首先会为dict()的参数构造一个dict,然后会为要创建的实际dict实例创建第二个dict。花括号一步创建了dict实例。
NeilG

56

文字速度要快得多,因为它使用优化的BUILD_MAP和STORE_MAP操作码,而不是通用的CALL_FUNCTION:

> 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
@Ned:对于大多数用户而言,大多数时候都没有关系,但是在某些情况下,正在创建数百万或数十亿美元,并且2倍加速是有意义的。
Fooz先生2012年

5
@MrFooz:有这样的情况。我认为您会发现99.9%的人在进行微调时不在这种情况下。
Ned Batchelder

29
@Ned它与线程相关,但询问哪个更快。
艾略特(Elliott)

11
@Elliot OP没有问哪个更快。
汤姆·弗格森

5
如果要从源中的dict文字中生成数百万个dict或一个具有数百万个键的dict,那么您做错了。
jwg

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

除了您已经指出的,Python的词汇规则会干扰之外,这两种方法产生的字典相同。

字典文字显然是字典,您可以创建任何类型的键,但需要引用键名称。另一方面,由于某些原因,您可以将变量用于键:

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

dict()构造给你因为各种输入的形式它需要更多的灵活性。例如,您可以为其提供一个成对的迭代器,并将其视为键/值对。

我不知道为什么PyCharm会提议将一种形式转换为另一种形式。


2
好吧,我想PyCharm只是想变得更好。正如似乎总是提供将单引号字符串转换为双引号一样-没有明显的原因。
马里格林2011年

1
如果您的密钥是字符串,则只需要引用密钥即可。它们可能很容易成为浮动的floatsets的元组,尽管这可能会变得很难看。
Wooble 2011年


6

从python 2.7教程开始:

一对大括号创建一个空字典:{}。将以逗号分隔的key:value对列表放在大括号内会为字典添加初始的key:value对;这也是将字典写在输出上的方式。

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。

尽管如此,我仍然更喜欢始终使用set字面量,因为我认为它应该更具可读性和个人喜好。


我经常忘记set存在s 的字面语法。我希望排序命令有字面意义的语法...可以肯定的是,我比集合更经常使用它们。
ArtOfWarfare

2

当您从其他对象(无python)复制粘贴值时,dict()文字很不错(例如,环境变量列表)。如果您有bash文件,请说

FOO='bar'
CABBAGE='good'

您可以轻松地将其粘贴到dict()文字中并添加注释。这也使相反的操作变得容易,将其复制到其他内容中。而{'FOO': 'bar'}语法是非常独特的蟒蛇和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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.