¿Cuál es la diferencia entre dict () y {}?

Así que digamos que quiero hacer un diccionario. Lo llamaremos d . ¡Pero hay varias formas de inicializar un diccionario en Python! Por ejemplo, podría hacer esto:

 d = {'hash': 'bang', 'slash': 'dot'} 

O podría hacer esto:

 d = dict(hash='bang', slash='dot') 

O esto, curiosamente:

 d = dict({'hash': 'bang', 'slash': 'dot'}) 

O esto:

 d = dict([['hash', 'bang'], ['slash', 'dot']]) 

Y toda otra multitud de formas con la función dict() . Así que, obviamente, una de las cosas que proporciona dict() es la flexibilidad en la syntax y la inicialización. Pero eso no es lo que estoy preguntando.

Digamos que tenía que hacer d un diccionario vacío. ¿Qué sucede detrás de la escena del intérprete de Python cuando hago d = {} contra d = dict() ? ¿Son simplemente dos formas de hacer lo mismo? ¿El uso de {} tiene la llamada adicional de dict() ? ¿Uno tiene (incluso despreciable) más gastos generales que el otro? Si bien la pregunta no tiene ninguna importancia, es una curiosidad que me encantaría haber respondido.

 >>> def f(): ... return {'a' : 1, 'b' : 2} ... >>> def g(): ... return dict(a=1, b=2) ... >>> g() {'a': 1, 'b': 2} >>> f() {'a': 1, 'b': 2} >>> import dis >>> dis.dis(f) 2 0 BUILD_MAP 0 3 DUP_TOP 4 LOAD_CONST 1 ('a') 7 LOAD_CONST 2 (1) 10 ROT_THREE 11 STORE_SUBSCR 12 DUP_TOP 13 LOAD_CONST 3 ('b') 16 LOAD_CONST 4 (2) 19 ROT_THREE 20 STORE_SUBSCR 21 RETURN_VALUE >>> dis.dis(g) 2 0 LOAD_GLOBAL 0 (dict) 3 LOAD_CONST 1 ('a') 6 LOAD_CONST 2 (1) 9 LOAD_CONST 3 ('b') 12 LOAD_CONST 4 (2) 15 CALL_FUNCTION 512 18 RETURN_VALUE 

dict () es aparentemente algo de C incorporado. Una persona realmente inteligente o dedicada (no yo) podría mirar la fuente del intérprete y decirle más. Sólo quería presumir dis.dis. 🙂

En cuanto al rendimiento va:

 >>> from timeit import timeit >>> timeit("a = {'a': 1, 'b': 2}") 0.424... >>> timeit("a = dict(a = 1, b = 2)") 0.889... 

@Jacob: Hay una diferencia en la forma en que se asignan los objetos, pero no son copia-en-escritura. Python asigna una “lista gratuita” de tamaño fijo donde puede asignar rápidamente objetos de diccionario (hasta que se llene). Los diccionarios asignados a través de la syntax {} (o una llamada de C a PyDict_New ) pueden provenir de esta lista gratuita. Cuando el diccionario ya no está referenciado, vuelve a la lista libre y ese bloque de memoria se puede reutilizar (aunque los campos se restablecen primero).

Este primer diccionario se devuelve inmediatamente a la lista gratuita, y el siguiente reutilizará su espacio de memoria:

 >>> id({}) 340160 >>> id({1: 2}) 340160 

Si mantiene una referencia, el próximo diccionario vendrá de la siguiente ranura libre:

 >>> x = {} >>> id(x) 340160 >>> id({}) 340016 

Pero podemos eliminar la referencia a ese diccionario y liberar su ranura de nuevo:

 >>> del x >>> id({}) 340160 

Dado que la syntax {} se maneja en byte-code, puede usar esta optimización mencionada anteriormente. Por otro lado, dict() se maneja como un constructor de clase regular y Python usa el asignador de memoria genérico, que no sigue un patrón fácilmente predecible como la lista libre anterior.

Además, al ver compile.c de Python 2.6, con la syntax {} parece que dimensiona previamente la tabla hash en función de la cantidad de elementos que almacena, lo que se conoce en el momento del análisis.

Básicamente, {} es syntax y se maneja en un nivel de idioma y bytecode. dict () es simplemente otro componente con una syntax de inicialización más flexible. Tenga en cuenta que dict () solo se agregó en la mitad de la serie 2.x.

Actualización : gracias por las respuestas. Se eliminó la especulación sobre la copia en escritura.

Otra diferencia entre {} y dict es que dict siempre asigna un nuevo diccionario (incluso si el contenido es estático), mientras que {} no siempre lo hace (ver la respuesta de mgood para cuándo y por qué):

 def dict1(): return {'a':'b'} def dict2(): return dict(a='b') print id(dict1()), id(dict1()) print id(dict2()), id(dict2()) 

produce:

 $ ./mumble.py
 11642752 11642752
 11867168 11867456

No estoy sugiriendo que intentes aprovechar esto o no, depende de la situación en particular, solo señalarlo. (También es probable que se vea en el desassembly si comprende los códigos de operación).

dict () se utiliza cuando desea crear un diccionario a partir de una iterable, como:

 dict( generator which yields (key,value) pairs ) dict( list of (key,value) pairs ) 

Uso divertido:

 def func(**kwargs): for e in kwargs: print(e) a = 'I want to be printed' kwargs={a:True} func(**kwargs) a = 'I dont want to be printed' kwargs=dict(a=True) func(**kwargs) 

salida:

 I want to be printed a 

Para crear un conjunto vacío, deberíamos usar el conjunto de palabras clave antes de él, es decir, set() esto crea un conjunto vacío donde, como en los dictados, solo los paréntesis de las flores pueden crear un dict vacío.

Vamos con un ejemplo

 print isinstance({},dict) True print isinstance({},set) False print isinstance(set(),set) True