Existe-t-il une différence ultime entre les deux extraits de code suivants? Le premier attribue une valeur à une variable dans une fonction, puis renvoie cette variable. La deuxième fonction renvoie simplement la valeur directement.
Est-ce que Python les transforme en un bytecode équivalent? L'un d'entre eux est-il plus rapide?
Cas 1:
def func():
a = 42
return a
Cas 2:
def func():
return 42
Non, ce n'est pas le cas.
La compilation en code d'octet CPython est uniquement transmise via un petit optimiseur de judas conçu pour ne faire que des optimisations de base (voir test_peepholer.py dans la suite de tests pour plus d'informations sur ces optimisations. ).
Pour jeter un coup d'œil à ce qui va réellement se passer, utilisez dis
* pour voir les instructions générées. Pour la première fonction, contenant l'affectation:
from dis import dis
dis(func)
2 0 LOAD_CONST 1 (42)
2 STORE_FAST 0 (a)
3 4 LOAD_FAST 0 (a)
6 RETURN_VALUE
Alors que, pour la deuxième fonction:
dis(func2)
2 0 LOAD_CONST 1 (42)
2 RETURN_VALUE
Deux autres instructions (rapides) sont utilisées dans la première: STORE_FAST
et LOAD_FAST
. Celles-ci permettent de stocker et de récupérer rapidement la valeur dans le tableau fastlocals
du cadre d'exécution actuel. Ensuite, dans les deux cas, un RETURN_VALUE
Est effectué. Ainsi, la seconde est toujours légèrement plus rapide en raison du nombre réduit de commandes nécessaires à l'exécution.
En général, sachez que le compilateur CPython est conservatif dans les optimisations qu'il effectue. Ce n'est pas et ne cherche pas à être aussi intelligent que les autres compilateurs (qui, en général, ont aussi beaucoup plus d'informations à utiliser). L'objectif principal de la conception, en plus d'être manifestement correct, consiste à a) rester simple et b) à être aussi Swift que possible dans la compilation, de sorte que vous ne remarquiez même pas qu'une phase de compilation existe.
En fin de compte, vous ne devriez pas vous préoccuper de petits problèmes comme celui-ci. Le gain de vitesse est minime, constant et réduit au minimum par la surcharge induite par le fait que Python est interprété.
* dis
est un petit module Python qui désassemble votre code, vous pouvez l'utiliser pour voir le bytecode Python que le VM va exécuter.
Remarque: Comme indiqué également dans un commentaire de @Jorn Vernee, cela est spécifique à l'implémentation CPython de Python. D'autres implémentations peuvent faire des optimisations plus agressives si elles le souhaitent, mais pas CPython.
Les deux sont fondamentalement les mêmes sauf que dans le premier cas, l'objet 42
Est simplement attribué à une variable nommée a
ou, en d'autres termes, à des noms (c'est-à-dire a
) font référence à valeurs (ie 42
). Techniquement, il ne fait aucune tâche, en ce sens qu'il ne copie aucune donnée.
Alors que return
ing, cette liaison nommée a
est renvoyée dans le premier cas, tandis que l’objet 42
Est renvoyé dans le deuxième cas.
Pour plus de lecture, reportez-vous à ce superbe article de Ned Batchelder