Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

WBOY
WBOYke hadapan
2023-05-04 08:31:06858semak imbas

Kod bait biasa Python

LOAD_CONST

Arahan ini digunakan untuk memuatkan pemalar ke dalam tindanan. Pemalar boleh menjadi objek seperti nombor, rentetan, tupel, senarai, kamus, dll. Contohnya:

>>> dis.dis(lambda: 42)
  1           0 LOAD_CONST               1 (42)
              2 RETURN_VALUE

LOAD_NAME

Arahan ini digunakan untuk memuatkan pembolehubah ke dalam tindanan. Contohnya:

>>> dis.dis(lambda: x)
  1           0 LOAD_GLOBAL              0 (x)
              2 RETURN_VALUE
>>>

STORE_NAME

Arahan ini digunakan untuk menyimpan nilai pada bahagian atas tindanan ke dalam pembolehubah. Contohnya:

>>> dis.dis("x=42")
  1           0 LOAD_CONST               0 (42)
              2 STORE_NAME               0 (x)
              4 LOAD_CONST               1 (None)
              6 RETURN_VALUE

BINARY_ADD

Arahan ini digunakan untuk menambah dua nilai ​​​​pada bahagian atas tindanan dan menolak hasilnya ke tindanan.

>>> dis.dis(lambda: x + y)
  1           0 LOAD_GLOBAL              0 (x)
              2 LOAD_GLOBAL              1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE

BINARY_SUBTRACT

Arahan ini digunakan untuk menolak dua nilai ​​​​di bahagian atas tindanan dan menolak hasilnya ke tindanan.

>>> dis.dis(lambda: x - y)
  1           0 LOAD_GLOBAL              0 (x)
              2 LOAD_GLOBAL              1 (y)
              4 BINARY_SUBTRACT
              6 RETURN_VALUE

Kod bait yang sama untuk penambahan, penolakan, pendaraban dan pembahagian untuk mendapatkan baki adalah seperti berikut:

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

COMPARE_OP

Arahan ini digunakan untuk membandingkan dua nilai ​di bahagian atas tindanan, dan Hasil perbandingan ditolak ke tindanan Parameter bait seterusnya selepas kod bait ini mewakili simbol perbandingan kurang daripada, lebih besar daripada, tidak sama dengan, dsb. Contohnya:

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

RETURN_VALUE

Patikkan elemen atas tindanan sebagai nilai pulangan.

BUILD_LIST

Arahan ini digunakan untuk membuat senarai. Contohnya:

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

Arahan bytecode ini mempunyai parameter yang menunjukkan bilangan elemen senarai dalam ruang tindanan Dalam contoh di atas, parameter ini ialah 4.

BUILD_TUPLE

Arahan ini digunakan untuk mencipta tuple. Sebagai contoh:

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

Bytecode yang sama juga mempunyai parameter yang menunjukkan bilangan elemen untuk mencipta tuple.

BUILD_MAP

Arahan ini digunakan untuk mencipta kamus. Contohnya:

BUILD_SET

Seperti senarai dan tuple, arahan ini digunakan untuk mencipta objek koleksi Arahan yang sama juga mempunyai parameter yang menunjukkan bilangan elemen yang digunakan untuk mencipta koleksi.

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

BUILD_CONST_KEY_MAP

Arahan ini digunakan untuk mencipta objek kamus Perintah yang sama juga mempunyai parameter yang menunjukkan bilangan elemen dalam kamus.

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

Analisis prinsip penghias dari perspektif bytecode

Jika anda seorang pythoner, maka anda pasti pernah mendengar tentang penghias lebih kurang Ini adalah gula sintaks ular sawa yang boleh kita Gunakan ia untuk melakukan banyak perkara menarik, seperti menambah beberapa fungsi pada fungsi tanpa mengubah suai kod sumber, seperti mengira masa.

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

Dalam kod di atas, kami melaksanakan fungsi untuk mengira jujukan Fibonacci Selain itu, kami juga menulis fungsi eval_time untuk mengira masa pelaksanaan fungsi tersebut output program adalah seperti berikut:

>>>fib(10)
(55, 5.9604644775390625e-06)

Anda boleh lihat Mencapai kesan yang kita inginkan.

Sekarang kita menggunakan contoh yang lebih mudah untuk mensimulasikan struktur kod di atas, supaya kita boleh menganalisis proses pelaksanaan fungsi di atas:

s = """
def decorator(func):
    print("Hello")
    return func
 
@decorator
def fib(n):
    pass
"""
dis.dis(s)

Keluaran fungsi dis di atas sepadan dengan bait kod Kod adalah seperti berikut:

  2           0 LOAD_CONST               0 (", baris 2>)              4 JADIKAN_FUNGSI            0
              6 NAMA_KEDAI               0 (penghias)
 
  6           8 LOAD_NAME                ", baris 6> )
12 LOAD_CONST 3 ('fib')
14 Make_Function 0
16 CALL_FUNCTION 1
18 Store_Name 1 (fib)
20 LOAD_CONST 4 (NONE)
pembongkaran & lt; kod penghias objek di 0x108068d40, fail "& lt; dis & gt;", baris 2 & gt ;:
3 0 load_global 0 (cetak)
2 load_const 1 ('hello') Call_function 1
6 POP_TOP

4 8 LOAD_FAST 0 (FUNC)
10 RETURN_VALUE

6>:
  8           0 LOAD_CONST               0 (Tiada)
              2 PULANGAN_NILAI




执行完第二条指令 LOAD_CONST 之后,会将字符串 penghias 加载进入栈空间当中。

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

STORE_NAME,条字节码会将栈顶的元素弹出,并且将 co_names[oparg]码当中 co_names[oparg]就是 penghias 。

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

LOAD_NAME,这条字节码就是将 co_names[oparg]空间当中,也就是上面的 penghias 函数加入进行栈空间当中。

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

接下来的三条字节码 LOAD_CONST,LOAD_CONST 和和和和和和节码之后,栈空间如下所示:

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

接下来的一条指令非常重要,这条指令便是装饰器的核心原理,CALL_FUNCTION 这条指令有一个参数 i,在上面的字节码当中为 1,也就是说从栈顶开始的前 i 个元素都是函数参数,调用的函数在栈空间的位置为 i + 1 (从栈顶往下数),那么在上面的情况下就是说调用 decorator 函数,并且将 fib 函数作为 decorator 函数的参数,decorator 函数的返回值再压入栈顶。在上面的代码当中 decorator 函数返回值也是一个函数,也就是 decorator 函数的参数,即 fib 函数。

Bagaimana untuk melaksanakan penghias kod bait mesin maya Python

接下来便是 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 函数自己的返回值,因此才打印了字符串。

Atas ialah kandungan terperinci Bagaimana untuk melaksanakan penghias kod bait mesin maya Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam