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

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

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

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

dict构造函数中

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

这些不同的方法是否在某些重要方面有所不同?

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

Using PyCharm, I noticed it offers to convert a dict literal:

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

into a dict constructor:

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

Do these different approaches differ in some significant way?

(While writing this question I noticed that using dict() it seems impossible to specify a numeric key .. d = {1: 'one', 2: 'two'} is possible, but, obviously, dict(1='one' ...) is not. Anything else?)


回答 0

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

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

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

I think you have pointed out the most obvious difference. Apart from that,

the first doesn’t need to lookup dict which should make it a tiny bit faster

the second looks up dict in locals() and then globals() and the finds the builtin, so you can switch the behaviour by defining a local called dict for example although I can’t think of anywhere this would be a good idea apart from maybe when debugging


回答 1

文字速度要快得多,因为它使用优化的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

Literal is much faster, since it uses optimized BUILD_MAP and STORE_MAP opcodes rather than generic 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

回答 2

它们在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

They look pretty much the same on Python 3.2.

As gnibbler pointed out, the first doesn’t need to lookup dict, which should make it a tiny bit faster.

>>> 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

回答 3

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

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

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

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

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

These two approaches produce identical dictionaries, except, as you’ve noted, where the lexical rules of Python interfere.

Dictionary literals are a little more obviously dictionaries, and you can create any kind of key, but you need to quote the key names. On the other hand, you can use variables for keys if you need to for some reason:

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

The dict() constructor gives you more flexibility because of the variety of forms of input it takes. For example, you can provide it with an iterator of pairs, and it will treat them as key/value pairs.

I have no idea why PyCharm would offer to convert one form to the other.


回答 4

与python 3.4 + pycharm的一大不同是,如果键数超过256,则dict()构造函数会生成“语法错误”消息。

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

One big difference with python 3.4 + pycharm is that the dict() constructor produces a “syntax error” message if the number of keys exceeds 256.

I prefer using the dict literal now.


回答 5

从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()都产生字典,但是提供了一些不同的字典数据初始化方式。

From python 2.7 tutorial:

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.

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

While:

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.

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:

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

So both {} and dict() produce dictionary but provide a bit different ways of dictionary data initialization.


回答 6

我发现dict文字d = {'one': '1'}更具可读性,可以定义数据,而不是分配事物值并将它们发送给dict()构造函数。

另一方面,我看到人们错误地输入了dict文字,d = {'one', '1'}因为在现代python 2.7+中它将创建一个set。

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

I find the dict literal d = {'one': '1'} to be much more readable, your defining data, rather than assigning things values and sending them to the dict() constructor.

On the other hand i have seen people mistype the dict literal as d = {'one', '1'} which in modern python 2.7+ will create a set.

Despite this i still prefer to all-ways use the set literal because i think its more readable, personal preference i suppose.


回答 7

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

FOO='bar'
CABBAGE='good'

您可以轻松地将其粘贴到dict()文字中并添加注释。这也使相反的操作变得容易,将其复制到其他内容中。而{'FOO': 'bar'}语法是非常独特的Python和JSON。因此,如果您经常使用json,则可能需要使用{}带双引号的文字。

the dict() literal is nice when you are copy pasting values from something else (none python) For example a list of environment variables. if you had a bash file, say

FOO='bar'
CABBAGE='good'

you can easily paste then into a dict() literal and add comments. It also makes it easier to do the opposite, copy into something else. Whereas the {'FOO': 'bar'} syntax is pretty unique to python and json. So if you use json a lot, you might want to use {} literals with double quotes.


回答 8

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

class NestedDict(dict):

    # ... skipped

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

There is no dict literal to create dict-inherited classes, custom dict classes with additional methods. In such case custom dict class constructor should be used, for example:

class NestedDict(dict):

    # ... skipped

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

回答 9

还请考虑以下事实:与运算符匹配的标记不能在构造函数语法中使用,即,破折号。

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

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

Also consider the fact that tokens that match for operators can’t be used in the constructor syntax, i.e. dasherized keys.

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

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