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

Is there a difference between using a dict literal and a dict constructor?

使用pycharm,我注意到它提供了转换dict文本的功能:

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

到dict构造函数中:

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

这些不同的方法有什么显著的区别吗?

(在写这个问题的时候,我注意到使用dict()似乎不可能指定一个数字键。d = {1: 'one', 2: 'two'}是可能的,但显然,dict(1='one' ...)不是。还要别的吗?)


我想你已经指出了最明显的区别。除此之外,

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

第二种方法是在locals()中查找dict,然后查找globals()中的builtin,这样您就可以通过定义一个称为dict的本地变量来切换行为,尽管我想不出这是一个好主意,除了在调试时


文字速度更快,因为它使用优化的构建映射和存储映射操作码,而不是通用的调用函数:

1
2
3
4
5
6
7
8
9
10
11
> 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


它们在python3.2上看起来几乎是一样的。

正如Gnibbler指出的,第一个不需要查找dict,这会使它更快一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
>>> 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


这两种方法产生相同的字典,正如您所指出的,除了Python的词汇规则会干扰的地方。

字典文本是一个更明显的字典,您可以创建任何类型的键,但您需要引用键名。另一方面,如果出于某种原因需要,可以将变量用于键:

1
2
3
4
a ="hello"
d = {
    a: 'hi'
    }

dict()构造函数由于输入形式的多样性,给了您更多的灵活性。例如,您可以为它提供一个成对的迭代器,它将把它们当作键/值对来对待。

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


与python3.4+pycharm的一大区别是dict()构造函数如果键数超过256,则生成"语法错误"消息。

我现在更喜欢使用dict文字。


从python 2.7教程:

A pair of braces creates an empty
dictionary: {}. Placing a
comma-separated list of key:value
pairs within the braces adds initial
key:value pairs to the dictionary;
this is also the way dictionaries are
written on output.

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

而:

The dict() constructor builds
dictionaries directly from lists of
key-value pairs stored as tuples. When
the pairs form a pattern, list
comprehensions can compactly specify
the key-value list.

1
2
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)))

When the keys are simple strings, it
is sometimes easier to specify pairs
using keyword arguments:

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

因此,和dict()都生成字典,但提供了一些不同的字典数据初始化方法。


没有用于创建dict继承类的dict文本,也没有用于使用其他方法创建自定义dict类的dict文本。在这种情况下,应使用自定义dict类构造函数,例如:

1
2
3
4
5
6
7
8
class NestedDict(dict):

    # ... skipped

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

我发现dict-literal d = {'one': '1'}更易读,您定义的数据,而不是赋值并将其发送给dict()构造函数。

另一方面,我看到人们把dict文本错误地输入为d = {'one', '1'},在现代的python2.7+中,它将创建一个集合。

尽管如此,我仍然倾向于所有方式使用set-literal,因为我认为它更具可读性,我想是个人偏好。


另外,还要考虑这样一个事实:与运算符匹配的标记不能在构造函数语法中使用,即dasherized键。

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

>>> {'
foo-bar': 1}
{'
foo-bar': 1}

当您从其他对象(非python)复制粘贴值时,dict()文本很好。例如环境变量列表。如果你有bash文件,就说

1
2
FOO='bar'
CABBAGE='good'

您可以很容易地将其粘贴到dict()文本中并添加注释。它还可以更容易地做相反的事情,复制到其他东西中。而{'FOO': 'bar'}语法对于python和json来说是非常独特的。因此,如果您经常使用JSON,那么可能需要使用带双引号的{}文本。