[] et {} vs list () et dict (), quel est le meilleur?

113

Je comprends qu'ils sont tous les deux essentiellement la même chose, mais en termes de style, quel est le meilleur (le plus pythonique) à utiliser pour créer une liste vide ou un dict?

Noah McIlraith
la source

Réponses:

197

En termes de vitesse, il n'y a pas de concurrence pour les listes / dictionnaires vides:

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

et pour les non-vides:

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

De plus, l'utilisation de la notation entre crochets vous permet d'utiliser des compréhensions de liste et de dictionnaire, ce qui peut être une raison suffisante.

Greg Haskins
la source
4
La compréhension des dictionnaires et des listes peut également être effectuée en utilisant les noms anglais. Exemple:list(i for i in range(10) if i % 2)
Zags
4
y a-t-il une raison pour laquelle {} et [] sont tellement plus rapides? Je pensais que c'étaient simplement des alias.
Justin D.
L'heure ne semble pas donner l'heure exacte. Selon le benchmark, cela semble prendre environ 200 ms, ce qui est bien plus lent que les appels HTTP normaux. Essayez d'exécuter dict () normalement dans le shell puis exécutez timeit ("dict ()"), vous verriez une différence visible dans l'exécution.
piyush
2
@piyush En fait, la timeit()fonction signale le temps total pour exécuter un nombre spécifié d'itérations, ce qui est 1000000par défaut. Ainsi, les exemples ci-dessus indiquent le nombre de secondes pour exécuter l'extrait de code un million de fois. Par exemple timeit('dict()', number=1) // -> 4.0531158447265625e-06(une itération) while timeit('dict()') // -> 0.12412905693054199(un million d'itérations)
Greg Haskins
@GregHaskins donc dans ce cas, je ne vois pas qu'il faille s'inquiéter d'utiliser dict () ou {}, à moins de parcourir un million d'enregistrements et d'utiliser dict () dans la boucle.
piyush
37

À mon avis, []et {}sont les moyens les plus pythoniques et les plus lisibles de créer des listes / dictionnaires vides.

Se méfier de set() 's cependant, par exemple:

this_set = {5}
some_other_set = {}

Cela peut être déroutant. Le premier crée un ensemble avec un élément, le second crée un dict vide et non un ensemble.

orlp
la source
4
{}crée toujours un dict vide. {1,2,3}crée un ensemble dans 2.7+ mais il s'agit d'une erreur de syntaxe dans 2.6et les versions antérieures.
ThiefMaster
1
Désolé? c'est une variable avec un nom some_epic_setqui pointe vers un dictobjet vide ... ce n'est pas un ensemble vide. Pour un ensemble vide, vous devez utiliser set().
6502
2
@ 6502: En effet, mais c'est un piège courant qui {5}crée un ensemble avec un élément, 5et {}est un dict vide.
orlp
1
Wow, c'était déroutant. Pourtant, ce n'est pas le niveau de confusion de Fractal of Bad Design. :-)
Prof. Falken
4
@EnderLook: En fait, avec le déballage généralisé , vous pouvez utiliser {*()}pour créer un vide setavec une syntaxe littérale. Je l'appelle l'opérateur de singe borgne. :-)
ShadowRanger
17

Le littéral dict peut - être un petit peu plus vite que son bytecode est plus courte:

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

Il en va de même pour le listvs[]

ThiefMaster
la source
8
Cela suppose que BUILD_MAP et LOAD_GLOBAL sont à temps constant et prennent le même temps. Hautement improbable. timeit donne une bien meilleure estimation.
Jamie Pate
Plus probablement, CALL_FUNCTIONprend au moins autant de temps que BUILD_MAP(la fonction appelée est essentiellement BUILD_MAP), et LOAD_GLOBALprend juste une surcharge supplémentaire.
chepner
3

IMHO, en utilisant list()et dict()fait que votre Python ressemble à C. Ugh.

RichieHindle
la source
3

Dans le cas de la différence entre [] et list (), il y a un piège que je n'ai vu personne d'autre signaler. Si vous utilisez un dictionnaire comme membre de la liste, les deux donneront des résultats entièrement différents:

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
la source
Vous pouvez obtenir les mêmes résultats qu'en [foo_dict]utilisant list((foo_dict,)). La list()méthode prend un itérable car il ne s'agit que d'un paramètre et l'itère pour ajouter des éléments à la liste. Cela causera un piège similaire en faisant list(some_list)ce qui aplatira la liste.
sotrh
1

list () et [] fonctionnent différemment:

>>> 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 () crée toujours un nouvel objet dans le tas, mais [] peut réutiliser la cellule mémoire pour de nombreuses raisons.

Andreykyz
la source
0

il y a une différence de comportement entre [] et list () comme le montre l'exemple ci-dessous. nous devons utiliser list () si nous voulons que la liste des nombres soit renvoyée, sinon nous obtenons un objet map! Je ne sais pas comment l'expliquer.

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
la source
ici semble être une explication du comportement en utilisant l'exemple de la fonction range () >>> print (range (10)) # range (0, 10) range () se comporte comme une liste, mais ce n'est pas une liste. C'est un objet qui retourne les éléments successifs d'une séquence lorsque vous itérez dessus, il ne fait pas vraiment la liste, économisant de l'espace. un tel objet est itérable, c'est-à-dire qu'il convient comme cible pour les fonctions et les constructions qui attendent quelque chose à partir duquel elles peuvent obtenir des éléments successifs jusqu'à ce que l'offre soit épuisée. La fonction list () crée des listes à partir des itérables: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac
1
la conséquence est que [] stocke l'objet itérable; list () crée une liste à partir du même itérable
sebtac
0

Une paire de crochets correspond à un objet de liste ou à un indice d'index, ma_Liste [x].

Une paire d'accolades indique un objet dictionnaire.

a_list = ['activé', 'désactivé', 1, 2]

a_dict = {on: 1, off: 2}

Rohit Chaurasiya
la source
-5

C'est principalement une question de choix la plupart du temps. C'est une question de préférence.

Notez cependant que si vous avez des touches numériques par exemple, vous ne pouvez pas le faire:

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

Tu dois faire:

mydict = {"1":"foo", "2":"bar"}
Ikke
la source
7
C'est faux ... vous devez le faire mydict = {1:"foo", 2:"bar"}(sans guillemets pour les clés).
6502
8
Ce n'est pas simplement «faux». Les clés sont des chaînes / entiers selon que vous les citez ou non.
ThiefMaster