开发者

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

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


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


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


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


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.


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.


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.


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.


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.


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',
})


Super late to the party here, but if you have a kwargs function:

def foo(a=None, b=None):
    ...

And your splatting a dict like so:

d_1 = { 'a': 1, 'b': 2 }
d_2 = dict(a=1, b=2)

# This works
foo(**d_1)

# And this as well
foo(**d_2)

But d_2 may be better suited for refactoring argument names that may change in your foo signature. Since in d_1 they are strings.


Also, when it comes to reading code (which is a lot), I feel that the literal has less cognitive burden (because we associate literals to be something that is less "active" than say a dict() which looks like a function call which makes the brain wonder...at least for a micro second :)) compared to dict(), admittedly partly due to the syntax highlighting in the editor, but still very relevant on a daily basis (at least for me).

If I focus on the surrounding code around the dict statement represented as ..., a literal dict makes it a bit easier for me to understand the surrounding code :).

...
...
...
config = {
    'key1':"value1",
    'key2':"value2",
    'key3':"value3",
    'key4':"value4",
}
...
...
...

#****VS *****

...
...
...
config =dict(
    key1 = 'value1',
    key2 = 'value2',
    key3 = 'value3',
    key4 = 'value4',

)
...
...
...


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜