Comme nous le savons tous, Python n'est pas un langage à haute efficacité d'exécution. De plus, la boucle est une opération très chronophage dans n'importe quelle langue. Si une opération simple en une seule étape prend 1 unité de temps, si cette opération est répétée des dizaines de milliers de fois, le temps final augmentera de dizaines de milliers de fois.

whileet forsont deux mots-clés couramment utilisés en Python pour implémenter des boucles, et il existe en fait une lacune dans leur efficacité d'exécution. Par exemple, le code de test suivant :

import timeit


def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s


def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s


def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))


if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354

Il s'agit d'une simple opération de somme qui calcule la somme de tous les nombres naturels de 1 à n. Vous pouvez voir que la forboucle est while1,5 seconde plus rapide.

La différence réside principalement dans le mécanisme des deux.

Dans chaque boucle, whileil y a en fait deux opérations de forplus : la vérification des limites et il'incrémentation de la variable . Autrement dit, chaque fois que la boucle est exécutée, while effectuera une vérification des limites ( while i < n) et un calcul d'auto-incrémentation ( i +=1). Les deux étapes sont du code Python pur explicite.

forLes boucles n'ont pas besoin d'effectuer des opérations de vérification des limites et d'auto-incrémentation, et aucun code Python explicite n'est ajouté (le code Python pur est moins efficace que le code C de bas niveau). Lorsque le nombre de boucles est suffisamment grand, il y a un net écart d'efficacité.

Deux fonctions supplémentaires pourraient être ajoutées, ajoutant des contrôles de limites inutiles et des calculs d'auto-incrémentation à la forboucle :

import timeit


def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s


def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s


def for_loop_with_inc(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
        i += 1
    return s


def for_loop_with_test(n=100_000_000):
    s = 0
    for i in range(n):
        if i < n:
            pass
        s += i
    return s


def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
    print('for loop with increment\t\t',
          timeit.timeit(for_loop_with_inc, number=1))
    print('for loop with test\t\t', timeit.timeit(for_loop_with_test, number=1))


if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => for loop with increment          4.602369500091299
# => for loop with test               4.18337869993411

On peut voir que l'augmentation des opérations de vérification des limites et d'auto-incrémentation affecte grandement l'efficacité d'exécution de la forboucle .

Comme mentionné précédemment, l'interpréteur sous-jacent de Python et les fonctions intégrées sont implémentés en langage C. L'efficacité d'exécution du langage C est bien supérieure à celle de Python.

Pour l'opération ci-dessus consistant à calculer la somme des progressions arithmétiques, à l'aide de la sumfonction , l'efficacité d'exécution de la bouclefor peut être bien supérieure à ou .while

import timeit


def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s


def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s


def sum_range(n=100_000_000):
    return sum(range(n))


def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
    print('sum range\t\t', timeit.timeit(sum_range, number=1))


if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => sum range                0.8658821999561042

On peut voir qu'après avoir utilisé la fonction intégrée sumpour remplacer la boucle, l'efficacité d'exécution du code a été doublée.

sumL' opération d'accumulation de la fonction intégrée est en fait une sorte de boucle, mais elle est implémentée en langage C, et forl'opération de sommation dans la boucle est s += iimplémentée . C > Python.

Développez votre réflexion. Enfant, j'ai entendu des histoires d'enfance de Gauss calculant ingénieusement la somme de 1 à 100. La somme de 1…100 est (1 + 100) * 50. Cette méthode de calcul peut également s'appliquer à l'opération de sommation ci-dessus.

import timeit


def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s


def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s


def sum_range(n=100_000_000):
    return sum(range(n))


def math_sum(n=100_000_000):
    return (n * (n - 1)) // 2


def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
    print('sum range\t\t', timeit.timeit(sum_range, number=1))
    print('math sum\t\t', timeit.timeit(math_sum, number=1))


if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => sum range                0.8658821999561042
# => math sum                 2.400018274784088e-06

Le temps d'exécution de la somme mathématique finale est environ 2.4e-61 million de fois plus court. L'idée ici est que puisque l'efficacité de la boucle est faible, un morceau de code doit être répété des centaines de millions de fois.

Ne faites simplement pas de boucle et utilisez des formules mathématiques pour transformer des centaines de millions d'opérations de boucle en une seule étape. L'efficacité a naturellement été améliorée sans précédent.

Conclusion finale (un peu une personne devinette):

Le moyen le plus rapide d'implémenter une boucle --
--
-- est sans boucle

Pour Python, utilisez les fonctions intégrées dans la mesure du possible, en limitant au minimum le code Python pur dans les boucles.


* Avis de non-responsabilité : cet article est organisé sur Internet et les droits d'auteur appartiennent à l'auteur original. Si les informations de la source sont incorrectes ou enfreignent les droits, veuillez nous contacter pour la suppression ou l'autorisation.

Source : StarryLand

Références

Le moyen le plus rapide de boucler en Python - mCoding (https://youtu.be/Qgevy75co8c)
image