[] и {} против list () и dict (), что лучше?

113

Я понимаю, что они оба по сути одно и то же, но с точки зрения стиля, что лучше (более Pythonic) для создания пустого списка или dict?

Ной Макилрайт
источник

Ответы:

197

Что касается скорости, то здесь нет конкуренции для пустых списков / диктов:

>>> from timeit import timeit
>>> timeit("[]")
0.040084982867934334
>>> timeit("list()")
0.17704233359267718
>>> timeit("{}")
0.033620194745424214
>>> timeit("dict()")
0.1821558326547077

и для непустого:

>>> timeit("[1,2,3]")
0.24316302770330367
>>> timeit("list((1,2,3))")
0.44744206316727286
>>> timeit("list(foo)", setup="foo=(1,2,3)")
0.446036018543964
>>> timeit("{'a':1, 'b':2, 'c':3}")
0.20868602015059423
>>> timeit("dict(a=1, b=2, c=3)")
0.47635635255323905
>>> timeit("dict(bar)", setup="bar=[('a', 1), ('b', 2), ('c', 3)]")
0.9028228448029267

Кроме того, использование скобок позволяет вам использовать понимание списка и словаря, что может быть достаточной причиной.

Грег Хаскинс
источник
4
Для понимания словаря и списков также можно использовать английские имена. Пример:list(i for i in range(10) if i % 2)
Zags
4
есть ли причина, по которой {} и [] намного быстрее? Я думал, это просто псевдонимы.
Джастин Д.
Кажется, что время не дает точного времени. Согласно тесту, это занимает ~ 200 мс, что намного медленнее, чем обычные HTTP-вызовы. Попробуйте запустить dict () как обычно в оболочке, а затем запустите timeit ("dict ()"), вы увидите видимую разницу в выполнении.
пиюш
2
@piyush Фактически, timeit()функция сообщает общее количество времени на выполнение указанного количества итераций, которое установлено 1000000по умолчанию. Таким образом, приведенные выше примеры - это количество секунд для выполнения фрагмента кода миллион раз. Например timeit('dict()', number=1) // -> 4.0531158447265625e-06(одна итерация) while timeit('dict()') // -> 0.12412905693054199(миллион итераций)
Грег Хаскинс
@GregHaskins, поэтому в этом случае я не вижу, что стоит беспокоиться об использовании dict () или {}, если только не перебрать миллион записей и не использовать dict () в цикле.
пиюш
37

На мой взгляд , []и {}являются наиболее вещий и машиночитаемые способы создания пустых списков / dicts.

Однако будьте осторожны set(), например:

this_set = {5}
some_other_set = {}

Может сбивать с толку. Первый создает набор с одним элементом, второй создает пустой dict, а не набор.

orlp
источник
4
{}всегда создает пустой dict. {1,2,3}создает набор в 2.7+, но является синтаксической ошибкой в 2.6более ранних версиях.
ThiefMaster
1
Прости? это переменная с именем some_epic_set, указывающим на пустой dictобъект ... это не пустой набор. Для пустого набора нужно использовать set().
6502
2
@ 6502: Действительно, но это обычная ошибка, когда {5}создается набор с одним элементом, 5и {}это пустой dict.
orlp
1
Вау, это сбивало с толку. Тем не менее, это не сбивает с толку фрактал плохого дизайна. :-)
Проф. Фалькен
4
@EnderLook: Фактически, с обобщенной распаковкой вы можете использовать {*()}для создания пустого setс буквальным синтаксисом. Я называю это одноглазым оператором обезьяны. :-)
ShadowRanger 09
17

ДИКТ литерал может быть крошечными немного быстрее , так как его байткод короче:

In [1]: import dis
In [2]: a = lambda: {}
In [3]: b = lambda: dict()

In [4]: dis.dis(a)
  1           0 BUILD_MAP                0
              3 RETURN_VALUE

In [5]: dis.dis(b)
  1           0 LOAD_GLOBAL              0 (dict)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE

То же самое относится и к listvs[]

ThiefMaster
источник
8
Это предполагает, что BUILD_MAP и LOAD_GLOBAL являются постоянным временем и занимают одинаковое количество времени. Очень маловероятно. timeit дает гораздо лучшую оценку.
Jamie Pate
Скорее всего, CALL_FUNCTIONзанимает по крайней мере столько же времени, сколько BUILD_MAP(по сути вызываемая функция BUILD_MAP), а LOAD_GLOBALзанимает лишь дополнительные накладные расходы.
chepner
3

ИМХО, использование list()и dict()делает ваш Python похожим на C. Ух.

RichieHindle
источник
3

В случае разницы между [] и list () есть ловушка, на которую я не видел, чтобы кто-нибудь указал. Если вы используете словарь в качестве члена списка, они дадут совершенно разные результаты:

In [1]: foo_dict = {"1":"foo", "2":"bar"}

In [2]: [foo_dict]
Out [2]: [{'1': 'foo', '2': 'bar'}]

In [3]: list(foo_dict)
Out [3]: ['1', '2'] 
в следующий день
источник
Вы можете получить те же результаты, что и [foo_dict]при использовании list((foo_dict,)). list()Метод принимает итератор , поскольку это единственный параметр и итерацию над ним , чтобы добавить элементы в список. Это вызовет аналогичную ловушку, сделав list(some_list)список более плоским.
sotrh
1

list () и [] работают по-разному:

>>> def a(p=None):
...     print(id(p))
... 
>>> for r in range(3):
...     a([])
... 
139969725291904
139969725291904
139969725291904
>>> for r in range(3):
...     a(list())
... 
139969725367296
139969725367552
139969725367616

list () всегда создает новый объект в куче, но [] может повторно использовать ячейку памяти по многим причинам.

андрейкыз
источник
0

есть одно различие в поведении между [] и list (), как показано в примере ниже. нам нужно использовать list (), если мы хотим получить список чисел, иначе мы получим объект карты! Не знаю, как это объяснить.

sth = [(1,2), (3,4),(5,6)]
sth2 = map(lambda x: x[1], sth) 
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>

sth2 = [map(lambda x: x[1], sth)]
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>
type(sth2) # list 
type(sth2[0]) # map

sth2 = list(map(lambda x: x[1], sth))
print(sth2) #[2, 4, 6]
type(sth2) # list
type(sth2[0]) # int
sebtac
источник
здесь, похоже, объясняется поведение на примере функции range () >>> print (range (10)) # range (0, 10) range () ведет себя как список, но это не список. Это объект, который возвращает последовательные элементы из последовательности, когда вы перебираете ее, на самом деле он не составляет список, экономя место. такой объект является итеративным, то есть подходит в качестве цели для функций и конструкций, которые ожидают чего-то, от чего они могут получать последовательные элементы, пока запас не будет исчерпан. Функция list () создает списки из итераций: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac
1
следствием этого является то, что [] хранит итерируемый объект; list () создает список из того же итеративного объекта
sebtac
0

Пара квадратных скобок обозначает один из объектов списка или индекс индекса my_List [x].

Пара фигурных скобок обозначает объект словаря.

a_list = ['вкл', 'выкл', 1, 2]

a_dict = {вкл: 1, выкл: 2}

Рохит Чаурасия
источник
-5

В основном это вопрос выбора. Это вопрос предпочтений.

Однако обратите внимание, что, например, если у вас есть цифровые клавиши, вы не можете этого сделать:

mydict = dict(1="foo", 2="bar")

Ты должен сделать:

mydict = {"1":"foo", "2":"bar"}
Икке
источник
7
Это неправильно ... нужно делать mydict = {1:"foo", 2:"bar"}(без кавычек для ключей).
6502
8
Это не просто «неправильно». Ключи - это строки / целые числа, в зависимости от того, цитируете вы их или нет.
ThiefMaster