Tout d'abord, vous n'avez pas mesuré la vitesse de len()
vous avez mesuré la vitesse de création d'une liste ou d'un ensemble. en même temps que la vitesse de len()
.
Utilisez le --setup
argument de timeit
:
$ python -m timeit --setup "a=[1,2,3,4,5,6,7,8,9,10]" "len(a)"
10000000 loops, best of 3: 0.0369 usec per loop
$ python -m timeit --setup "a={1,2,3,4,5,6,7,8,9,10}" "len(a)"
10000000 loops, best of 3: 0.0372 usec per loop
Les déclarations que vous passez à --setup
sont exécutées avant de mesurer la vitesse de len()
.
Deuxièmement, vous devez noter que len(a)
est une déclaration assez rapide. Le processus de mesure de sa vitesse peut être sujet au "bruit". Considérez que le code exécuté (et mesuré) par timeit est équivalent à ce qui suit :
for i in itertools.repeat(None, number):
len(a)
Parce que les deux len(a)
y itertools.repeat(...).__next__()
sont des opérations rapides et leurs vitesses peuvent être similaires, la vitesse de la itertools.repeat(...).__next__()
peut influencer les délais.
Pour cette raison, vous feriez mieux de mesurer len(a); len(a); ...; len(a)
(répété une centaine de fois) de sorte que le corps de la boucle for prend beaucoup plus de temps que l'itérateur :
$ python -m timeit --setup "a=[1,2,3,4,5,6,7,8,9,10]" "$(for i in {0..1000}; do echo "len(a)"; done)"
10000 loops, best of 3: 29.2 usec per loop
$ python -m timeit --setup "a={1,2,3,4,5,6,7,8,9,10}" "$(for i in {0..1000}; do echo "len(a)"; done)"
10000 loops, best of 3: 29.3 usec per loop
(Les résultats indiquent toujours que len()
a les mêmes performances sur les listes et les ensembles, mais maintenant vous êtes sûr que le résultat est correct).
Troisièmement, il est vrai que la "complexité" et la "vitesse" sont liées, mais je crois que vous faites une confusion. Le fait que len()
a O(1) complexité pour les listes et les ensembles n'implique pas qu'il doive fonctionner avec la même vitesse sur les listes et les ensembles.
Cela signifie que, en moyenne, quelle que soit la longueur de la liste a
est, len(a)
effectue le même nombre asymptotique d'étapes. Et peu importe la longueur de l'ensemble b
est, len(b)
effectue le même nombre asymptotique d'étapes. Mais l'algorithme pour calculer la taille des listes et des ensembles peut être différent, ce qui entraîne des performances différentes (timeit montre que ce n'est pas le cas, mais cela peut être une possibilité).
Enfin,
Si la création d'un objet set prend plus de temps que la création d'une liste, quelle en est la raison ?
Un ensemble, comme vous le savez, n'autorise pas les éléments répétés. Les ensembles dans CPython sont implémentés en tant que tables de hachage (pour garantir une valeur moyenne des éléments). O(1) insertion et consultation) : la construction et la maintenance d'une table de hachage sont beaucoup plus complexes que l'ajout d'éléments à une liste.
Plus précisément, lors de la construction d'un ensemble, vous devez calculer des hachages, construire la table de hachage, la consulter pour éviter d'insérer des événements en double, etc. En revanche, les listes dans CPython sont implémentées comme un simple tableau de pointeurs qui est malloc()
ed et realloc()
au besoin.