[] e {} vs list () e dict (), o que é melhor?

113

Eu entendo que ambos são essencialmente a mesma coisa, mas em termos de estilo, qual é o melhor (mais pitônico) para usar para criar uma lista vazia ou dict?

Noah McIlraith
fonte

Respostas:

197

Em termos de velocidade, não há competição por listas / dictos vazios:

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

e para não vazio:

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

Além disso, usar a notação de colchetes permite que você use as compreensões de lista e dicionário, o que pode ser motivo suficiente.

Greg Haskins
fonte
4
Compreensões de ditado e lista podem ser feitas usando os nomes em inglês também. Exemplo:list(i for i in range(10) if i % 2)
Zags de
4
há uma razão pela qual {} e [] são muito mais rápidos? Achei que fossem simplesmente pseudônimos.
Justin D.
O tempo não parece fornecer o tempo preciso. De acordo com o benchmark, parece levar ~ 200ms, que é muito mais lento do que as chamadas http normais. Tente executar o dict () normalmente no shell e depois execute o timeit ("dict ()"), você verá uma diferença visível na execução.
piyush
2
@piyush Na verdade, a timeit()função relata a quantidade total de tempo para executar um número especificado de iterações, que é 1000000por padrão. Portanto, os exemplos acima são o número de segundos para executar o snippet de código um milhão de vezes. Por exemplo timeit('dict()', number=1) // -> 4.0531158447265625e-06(uma iteração) while timeit('dict()') // -> 0.12412905693054199(um milhão de iterações)
Greg Haskins
@GregHaskins, então, nesse caso, não vejo que se deva se preocupar em usar dict () ou {}, a menos que percorra um milhão de registros e use dict () no loop.
piyush de
37

Na minha opinião []e {}são as formas mais pítônicas e legíveis de criar listas / dictos vazios.

set()Porém, tenha cuidado com o, por exemplo:

this_set = {5}
some_other_set = {}

Pode ser confuso. O primeiro cria um conjunto com um elemento, o segundo cria um dicionário vazio e não um conjunto.

orlp
fonte
4
{}sempre cria um dicionário vazio. {1,2,3}cria um conjunto no 2.7+, mas é um erro de sintaxe em 2.6versões anteriores.
ThiefMaster
1
Desculpe? essa é uma variável com nome some_epic_setque está apontando para um dictobjeto vazio ... não é um conjunto vazio. Para um conjunto vazio, você precisa usar set().
6502
2
@ 6502: Sim, mas é uma armadilha comum {5}criar um conjunto com um elemento 5e {}é um dicionário vazio.
orlp
1
Uau, isso foi confuso. Ainda assim, não é o nível Fractal de Mau Design confuso. :-)
Prof. Falken
4
@EnderLook: Na verdade, com a descompactação generalizada , você pode usar {*()}para fazer um vazio setcom a sintaxe literal. Eu chamo isso de operador de macaco caolho. :-)
ShadowRanger
17

O literal dict pode ser um minúsculo pouco mais rápido como seu bytecode é mais curto:

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

O mesmo se aplica ao listvs[]

ThiefMaster
fonte
8
Isso pressupõe que BUILD_MAP e LOAD_GLOBAL são tempos constantes e levam a mesma quantidade de tempo. Altamente improvável. timeit dá uma estimativa muito melhor.
Jamie Pate de
Mais provavelmente, CALL_FUNCTIONleva pelo menos tanto tempo quanto BUILD_MAP(a função que está sendo chamada essencialmente BUILD_MAP) e LOAD_GLOBALleva apenas uma sobrecarga adicional.
chepner de
3

IMHO, usando list()e dict()faz seu Python parecer C. Ugh.

RichieHindle
fonte
3

No caso de diferença entre [] e list (), há uma armadilha que não vi ninguém apontar. Se você usar um dicionário como membro da lista, os dois fornecerão resultados totalmente diferentes:

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'] 
oxtay
fonte
Você pode obter os mesmos resultados que [foo_dict]usando list((foo_dict,)). O list()método pega um iterável como único parâmetro e itera sobre ele para adicionar elementos à lista. Isso causará uma armadilha semelhante, o list(some_list)que achatará a lista.
sotrh
1

list () e [] funcionam de forma diferente:

>>> 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 () sempre cria um novo objeto no heap, mas [] pode reutilizar a célula de memória por vários motivos.

andreykyz
fonte
0

há uma diferença de comportamento entre [] e list () como mostra o exemplo abaixo. precisamos usar list () se quisermos que a lista de números seja retornada, caso contrário, obteremos um objeto de mapa! Não tenho certeza de como explicar isso.

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
fonte
aqui parece haver uma explicação do comportamento usando o exemplo da função range () >>> print (range (10)) # range (0, 10) range () se comporta como uma lista, mas não é uma lista. É um objeto que retorna os itens sucessivos de de uma sequência quando você itera sobre ela, ele realmente não faz a lista, economizando espaço. tal objeto é iterável, isto é, adequado como alvo para funções e construções que esperam algo do qual possam obter itens sucessivos até que o suprimento se esgote. A função list () cria listas de iteráveis: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac
1
a consequência é que [] armazena o objeto iterável; list () cria uma lista do mesmo iterável
sebtac de
0

Um par de colchetes denota um de um objeto de lista, ou um índice subscrito, my_List [x].

Um par de chaves denota um objeto de dicionário.

a_list = ['ligado', 'desligado', 1, 2]

a_dict = {on: 1, off: 2}

Rohit Chaurasiya
fonte
-5

É principalmente uma questão de escolha na maioria das vezes. É uma questão de preferência.

Observe, porém, que se você tiver teclas numéricas, por exemplo, não poderá fazer:

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

Você tem que fazer:

mydict = {"1":"foo", "2":"bar"}
Ikke
fonte
7
Isso está errado ... você precisa fazer mydict = {1:"foo", 2:"bar"}(sem as aspas para as chaves).
6502
8
Não é simplesmente "errado". As chaves são strings / ints dependendo se você as cita ou não.
ThiefMaster