[] y {} vs list () y dict (), ¿cuál es mejor?

113

Entiendo que ambos son esencialmente lo mismo, pero en términos de estilo, ¿cuál es el mejor (más Pythonic) para usar para crear una lista vacía o un dictado?

Noah McIlraith
fuente

Respuestas:

197

En términos de velocidad, no hay competencia para listas / dictados vacíos:

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

y para no vacíos:

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

Además, el uso de la notación entre corchetes le permite usar listas y comprensiones de diccionario, lo que puede ser motivo suficiente.

Greg Haskins
fuente
4
Las comprensiones de dictados y listas también se pueden hacer usando los nombres en inglés. Ejemplo:list(i for i in range(10) if i % 2)
Zags
4
¿Hay alguna razón por la que {} y [] sean mucho más rápidos? Pensé que eran simplemente alias.
Justin D.
La hora no parece dar una hora exacta. Según el punto de referencia, parece tardar ~ 200 ms, que es mucho más lento que las llamadas http normales. Intente ejecutar dict () normalmente en el shell y luego ejecute timeit ("dict ()"), verá una diferencia visible en la ejecución.
piyush
2
@piyush En realidad, la timeit()función informa la cantidad total de tiempo para ejecutar un número específico de iteraciones, que es la 1000000predeterminada. Entonces, los ejemplos anteriores son la cantidad de segundos para ejecutar el fragmento de código un millón de veces. Por ejemplo timeit('dict()', number=1) // -> 4.0531158447265625e-06(una iteración) mientras timeit('dict()') // -> 0.12412905693054199(un millón de iteraciones)
Greg Haskins
@GregHaskins, así que en ese caso, no veo que uno deba preocuparse por usar dict () o {}, a menos que recorra un millón de registros y use dict () en el ciclo.
piyush
37

En mi opinión []y {}son las formas más pitónicas y legibles de crear listas / dictados vacíos.

Tenga cuidado con set(), por ejemplo:

this_set = {5}
some_other_set = {}

Puede resultar confuso. El primero crea un conjunto con un elemento, el segundo crea un dict vacío y no un conjunto.

orlp
fuente
4
{}siempre crea un dict vacío. {1,2,3}crea un conjunto en 2.7+ pero es un error de sintaxis en 2.6y versiones anteriores.
ThiefMaster
1
¿lo siento? esa es una variable con nombre some_epic_setque apunta a un dictobjeto vacío ... no es un conjunto vacío. Para un juego vacío necesitas usar set().
6502
2
@ 6502: De hecho, pero es un error común que {5}crea un conjunto con un elemento 5y {}es un dict vacío.
orlp
1
Vaya, eso fue confuso. Aún así, no es el nivel de confusión de Fractal of Bad Design. :-)
Prof. Falken
4
@EnderLook: En realidad, con el desempaquetado generalizado , puede usar {*()}para hacer un vacío setcon sintaxis literal. Yo lo llamo el operador del mono tuerto. :-)
ShadowRanger
17

El literal dict podría ser un pequeño poco más rápido como su código de bytes es más corto:

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

Lo mismo se aplica al listvs[]

ThiefMaster
fuente
8
Esto supone que BUILD_MAP y LOAD_GLOBAL son tiempos constantes y toman la misma cantidad de tiempo. Altamente improbable. timeit da una estimación mucho mejor.
Jamie Pate
Lo más probable es que CALL_FUNCTIONtome al menos tanto tiempo como BUILD_MAP(la función que se llama esencialmente BUILD_MAP), y solo LOAD_GLOBALrequiere una sobrecarga adicional.
chepner
3

En mi humilde opinión, usando list()y dict()hace que su Python se vea como C. Ugh.

RichieHindle
fuente
3

En el caso de la diferencia entre [] y list (), hay un error que no he visto señalar a nadie más. Si usa un diccionario como miembro de la lista, los dos darán resultados completamente 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
fuente
Puede obtener los mismos resultados que [foo_dict]utilizando list((foo_dict,)). El list()método toma un iterable como único parámetro y lo repite para agregar elementos a la lista. Esto provocará un error similar al hacerlo, list(some_list)lo que aplanará la lista.
sotrh
1

list () y [] funcionan de manera 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 () siempre crea un nuevo objeto en el montón, pero [] puede reutilizar la celda de memoria por muchas razones.

andreykyz
fuente
0

hay una diferencia de comportamiento entre [] y list () como muestra el ejemplo siguiente. necesitamos usar list () si queremos que se devuelva la lista de números, de lo contrario, obtenemos un objeto de mapa. Aunque no estoy seguro de cómo explicarlo.

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
fuente
aquí parece haber una explicación del comportamiento usando un ejemplo de la función range () >>> print (range (10)) # range (0, 10) range () se comporta como una lista, pero no es una lista. Es un objeto que devuelve los elementos sucesivos de una secuencia cuando iteras sobre él, realmente no hace la lista, ahorrando espacio. tal objeto es iterable, es decir, adecuado como objetivo para funciones y construcciones que esperan algo de lo que puedan obtener elementos sucesivos hasta que se agote el suministro. La función list () crea listas a partir de iterables: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac
1
la consecuencia es que [] almacena el objeto iterable; list () crea una lista del mismo iterable
sebtac
0

Un par de corchetes denota uno de un objeto de lista, o un subíndice de índice, my_List [x].

Un par de llaves denota un objeto de diccionario.

a_list = ['encendido', 'apagado', 1, 2]

a_dict = {encendido: 1, apagado: 2}

Rohit Chaurasiya
fuente
-5

Es principalmente una cuestión de elección la mayor parte del tiempo. Es una cuestión de preferencia.

Sin embargo, tenga en cuenta que si tiene teclas numéricas, por ejemplo, eso no puede hacer:

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

Tu tienes que hacer:

mydict = {"1":"foo", "2":"bar"}
Ikke
fuente
7
Esto está mal ... debe hacerlo mydict = {1:"foo", 2:"bar"}(sin comillas para las claves).
6502
8
No es simplemente "incorrecto". Las claves son cadenas / ints dependiendo de si las cita o no.
ThiefMaster