Есть ли разница между использованием литерала dict и конструктора dict?

Используя PyCharm, я заметил, что он предлагает преобразовать dict literal:

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

в конструктор dict:

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

Различаются ли эти разные подходы каким-то значительным образом?

(При написании этого вопроса я заметил, что использование dict() представляется невозможным для указания числового ключа.. d = {1: 'one', 2: 'two'} возможно, но, очевидно, dict(1='one' ...) нет. Что-нибудь еще?)

Ответ 1

Я думаю, вы указали на самую очевидную разницу. Кроме того,

первый не нуждается в поиске dict, который должен сделать его немного быстрее

вторая просматривает dict в locals(), а затем globals() и находит встроенное значение, поэтому вы можете переключить поведение, указав локальный, называемый dict, например, хотя я не могу придумать нигде этого было бы хорошей идеей, кроме, может быть, при отладке

Ответ 2

Literal намного быстрее, поскольку использует оптимизированные коды операций 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

Ответ 3

Они выглядят почти так же на Python 3.2.

Как отметил гнибблер, первое не нужно искать 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

Ответ 4

Эти два подхода создают идентичные словари, за исключением, как вы отметили, где мешают лексические правила Python.

Словарь-литералы - это немного более очевидные словари, и вы можете создать любой тип ключа, но вам нужно указать ключевые имена. С другой стороны, вы можете использовать переменные для ключей, если вам нужно по какой-то причине:

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

Конструктор dict() дает вам большую гибкость из-за разнообразия форм ввода, которые он принимает. Например, вы можете предоставить ему итератор пар, и он будет рассматривать их как пары ключ/значение.

Я не знаю, почему PyCharm предложит преобразовать одну форму в другую.

Ответ 5

Одна большая разница с python 3.4 + pycharm заключается в том, что конструктор dict() выдает сообщение "синтаксическая ошибка", если количество ключей превышает 256.

Я предпочитаю теперь использовать литерал dict.

Ответ 6

Из учебника python 2.7:

Пара фигурных скобок создает пустую Словарь: {}. Размещение список ключей, разделенных запятыми: 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() создают словарь, но предоставляют несколько разных способов инициализации данных словаря.

Ответ 7

Нет никакого литерала dict для создания унаследованных dict-классов, пользовательских классов dict с дополнительными методами. В этом случае следует использовать конструктор класса пользовательского типа, например:

class NestedDict(dict):

    # ... skipped

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

Ответ 8

Я нахожу, что dict literal d = {'one': '1'} гораздо читабельнее, ваши определяющие данные, вместо того, чтобы присваивать значения вещей и отправлять их конструктору dict().

С другой стороны, я видел, как люди ошибаются в dict literal как d = {'one', '1'}, который в современном python 2.7+ создаст набор.

Несмотря на это, я по-прежнему предпочитаю использовать все пути, используя набор литералов, потому что я думаю, что его более читаемые личные предпочтения я предполагаю.

Ответ 9

литерал dict() хорош, когда вы копируете значения из чего-то другого (ни один python) Например, список переменных среды. если у вас есть файл bash, скажем

FOO='bar'
CABBAGE='good'

вы можете легко вставить затем в литерал dict() и добавить комментарии. Это также упрощает выполнение противоположных действий, копируя их во что-то другое. В то время как синтаксис {'FOO': 'bar'} довольно уникален для python и json. Поэтому, если вы много используете json, вы можете использовать литералы {} с двойными кавычками.

Ответ 10

Также рассмотрим тот факт, что токены, которые соответствуют операторам, не могут использоваться в синтаксисе конструктора, то есть в ключах, выделенных dasherized.

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

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