Cette instruction est utilisée pour charger une constante sur la pile. Les constantes peuvent être des objets tels que des nombres, des chaînes, des tuples, des listes, des dictionnaires, etc. Par exemple :
>>> dis.dis(lambda: 42) 1 0 LOAD_CONST 1 (42) 2 RETURN_VALUE
Cette instruction permet de charger une variable dans la pile. Par exemple :
>>> dis.dis(lambda: x) 1 0 LOAD_GLOBAL 0 (x) 2 RETURN_VALUE >>>
Cette instruction est utilisée pour stocker la valeur en haut de la pile dans une variable. Par exemple :
>>> dis.dis("x=42") 1 0 LOAD_CONST 0 (42) 2 STORE_NAME 0 (x) 4 LOAD_CONST 1 (None) 6 RETURN_VALUE
Cette instruction permet d'ajouter les deux valeurs en haut de la pile et de pousser le résultat vers la pile.
>>> dis.dis(lambda: x + y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_ADD 6 RETURN_VALUE
Cette instruction est utilisée pour soustraire les deux valeursen haut de la pile et pousser le résultat vers la pile.
>>> dis.dis(lambda: x - y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_SUBTRACT 6 RETURN_VALUE
Le même bytecode pour l'addition, la soustraction, la multiplication et la division pour obtenir le reste est le suivant :
>>> dis.dis(lambda: x + y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_ADD 6 RETURN_VALUE >>> dis.dis(lambda: x - y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_SUBTRACT 6 RETURN_VALUE >>> dis.dis(lambda: x * y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_MULTIPLY 6 RETURN_VALUE >>> dis.dis(lambda: x / y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_TRUE_DIVIDE 6 RETURN_VALUE >>> dis.dis(lambda: x // y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_FLOOR_DIVIDE 6 RETURN_VALUE >>> dis.dis(lambda: x % y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_MODULO 6 RETURN_VALUE
Cette instruction est utilisée pour comparer le haut de la pile Deux valeurs et pousser le résultat de la comparaison sur la pile. Le paramètre de l'octet suivant après ce bytecode représente le symbole de comparaison inférieur à, supérieur à, non égal à, etc. Par exemple :
>>> dis.dis(lambda: x - y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 BINARY_SUBTRACT 6 RETURN_VALUE >>> dis.dis(lambda: x > y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 COMPARE_OP 4 (>) 6 RETURN_VALUE >>> dis.dis(lambda: x < y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 COMPARE_OP 0 (<) 6 RETURN_VALUE >>> dis.dis(lambda: x != y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 COMPARE_OP 3 (!=) 6 RETURN_VALUE >>> dis.dis(lambda: x <= y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 COMPARE_OP 1 (<=) 6 RETURN_VALUE >>> dis.dis(lambda: x >= y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 COMPARE_OP 5 (>=) 6 RETURN_VALUE >>> dis.dis(lambda: x == y) 1 0 LOAD_GLOBAL 0 (x) 2 LOAD_GLOBAL 1 (y) 4 COMPARE_OP 2 (==) 6 RETURN_VALUE
Insérez l'élément supérieur de la pile comme valeur de retour.
Cette commande permet de créer une liste. Par exemple :
>>> dis.dis(lambda: [a, b, c, e]) 1 0 LOAD_GLOBAL 0 (a) 2 LOAD_GLOBAL 1 (b) 4 LOAD_GLOBAL 2 (c) 6 LOAD_GLOBAL 3 (e) 8 BUILD_LIST 4 10 RETURN_VALUE
Cette instruction de bytecode a un paramètre indiquant le nombre d'éléments de liste dans l'espace de pile. Dans l'exemple ci-dessus, ce paramètre est 4.
Cette commande permet de créer un tuple. Par exemple :
>>> dis.dis(lambda: (a, b, c)) 1 0 LOAD_GLOBAL 0 (a) 2 LOAD_GLOBAL 1 (b) 4 LOAD_GLOBAL 2 (c) 6 BUILD_TUPLE 3 8 RETURN_VALUE
Le même bytecode a également un paramètre, indiquant le nombre d'éléments pour créer un tuple.
Cette commande permet de créer un dictionnaire. Par exemple :
Comme la liste et le tuple, cette instruction permet de créer un objet de collection De même, cette instruction possède également un paramètre indiquant la valeur utilisée pour créer un objet de collection. collection. Le nombre d’éléments.
>>> dis.dis(lambda: {a, b, c, d}) 1 0 LOAD_GLOBAL 0 (a) 2 LOAD_GLOBAL 1 (b) 4 LOAD_GLOBAL 2 (c) 6 LOAD_GLOBAL 3 (d) 8 BUILD_SET 4 10 RETURN_VALUE
Cette commande est utilisée pour créer un objet dictionnaire. La même commande a également un paramètre, indiquant le nombre d'éléments dans le dictionnaire.
>>> dis.dis(lambda: {1:2, 3:4}) 1 0 LOAD_CONST 1 (2) 2 LOAD_CONST 2 (4) 4 LOAD_CONST 3 ((1, 3)) 6 BUILD_CONST_KEY_MAP 2 8 RETURN_VALUE
Si vous êtes un pythoneur, alors vous avez dû plus ou moins entendre parler des décorateurs, c'est un python On peut utilisez du sucre syntaxique pour faire beaucoup de choses intéressantes, comme ajouter certaines fonctions aux fonctions sans modifier le code source, comme calculer le temps.
import time def eval_time(func): def cal_time(*args, **kwargs): start = time.time() r = func(*args, **kwargs) end = time.time() return r, end - start return cal_time @eval_time def fib(n): a = 0 b = 1 while n > 0: n -= 1 a, b = b, a + b return a
Dans le code ci-dessus, nous avons implémenté une fonction pour calculer la séquence de Fibonacci. De plus, nous avons également écrit une fonction eval_time pour calculer le temps d'exécution de la fonction. le résultat du programme est le suivant :
Vous pouvez voir que l'effet souhaité est atteint. Maintenant, nous utilisons un exemple plus simple pour simuler la structure de code ci-dessus, afin que nous puissions analyser le processus d'exécution de la fonction ci-dessus :>>>fib(10)
#🎜 🎜#
(55, 5.9604644775390625e-06)
s = """ def decorator(func): print("Hello") return func @decorator def fib(n): pass """ dis.dis(s)
2 0 LOAD_CONST 0 (
MAKE_FUNCTION décorateur, objet de code条字节码会将栈顶砚元紴弹出,并且将 co_names[oparg] 指向这个对象,在上面的字节码当中 co_names[oparg] et décorateur.重新加载进入栈空间当中,也就是上面的 décorateur 函数加入进行栈空间当中。", ligne 2>)
2 LOAD_CONST 1 ('décorateur')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (décorateur)
6 8 LOAD_NAME 0 (décorateur)
7 10 LOAD_CONST 2 (", ligne 6>)
12 LOAD_CONST 3 ('fib')
14 MAKE_FUNCTION 0
16 CALL_FUNCTION 1
18 STORE_NAME 1 (fib)
20 LOAD_CONST 4 (Aucun)
22 RETURN_VALUE
Désassembler y du", ligne 2>:
3 0 LOAD_GLOBAL 0 (print)
0 (func)
10 RETURN_VALUE
Démontage de l'objet", ligne 6> :
8 0 LOAD_CONST 0 (Aucun)
2 RETURN_VALUE
执行第一条指令 LOAD_CONST,这条指令主要是加载一个 code object 对象,这个对象里面主要是包含函数 decorator 的字节码,主要是上面字Description du produit令 LOAD_CONST 之后,会将字符串 décorateur 加载进入栈空间当中。
接下来的三条字节码 LOAD_CONST,LOAD_CONST et MAKE_FUNCTION,空间如下所示:
接下来的一条指令非常重要,这条指令便是装饰器的核心原理,CALL_FUNCTION 这条指令有一个参数 i,在上面的字节码当中为 1,也就是说从栈顶开始的前 i 个元素都是函数参数,调用的函数在栈空间的位置为 i + 1 (从栈顶往下数),那么在上面的情况下就是说调用 decorator 函数,并且将 fib 函数作为 decorator 函数的参数,decorator 函数的返回值再压入栈顶。在上面的代码当中 decorator 函数返回值也是一个函数,也就是 decorator 函数的参数,即 fib 函数。
接下来便是 STORE_NAME 字节码,这条字节码的含义我们在前面已经说过了,就是将栈顶元素弹出,保存到 co_names[oparg] 指向的对象当中,在上面的代码当中也就是将栈顶的对象保存到 fib 当中。栈顶元素 fib 函数是调用函数 decorator 的返回值。
看到这里就能够理解了原来装饰器的最根本的原理不就是函数调用嘛,比如我们最前面的用于计算函数执行时间的装饰器的原理就是:
fib = eval_time(fib)
将 fib 函数作为 eval_time 函数的参数,再将这个函数的返回值保存到 fib 当中,当然这个对象必须是可调用的,不然后面使用 fib() 就会保存,我们可以使用下面的代码来验证这个效果。
def decorator(func): return func() @decorator def demo(): return "function demo return string : Demo" print(demo)
执行上面的程序结果为:
function demo return string : Demo
可以看到 demo 已经变成了一个字符串对象而不再是一个函数了,因为 demo = decorator(demo),而在函数 decorator 当中返回值是 demo 函数自己的返回值,因此才打印了字符串。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!