Есть ли разница между использованием литерала 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}