最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python虛擬機字節(jié)碼教程之裝飾器實現(xiàn)詳解

 更新時間:2023年04月11日 08:56:40   作者:一無是處的研究僧  
在本篇文章當中主要給大家介紹在?cpython?當中一些比較常見的字節(jié)碼,從根本上理解?python?程序的執(zhí)行。在本文當中主要介紹一些?python?基本操作的字節(jié)碼,并且將從字節(jié)碼的角度分析函數(shù)裝飾器的原理

Python 常見字節(jié)碼

LOAD_CONST

這個指令用于將一個常量加載到棧中。常量可以是數(shù)字、字符串、元組、列表、字典等對象。例如:

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

LOAD_NAME

這個指令用于將一個變量加載到棧中。例如:

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

STORE_NAME

這個指令用于將棧頂?shù)闹荡鎯Φ揭粋€變量中。例如:

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

這個指令用于對棧頂?shù)膬蓚€值進行加法運算并將結果推送到棧中。

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

BINARY_SUBTRACT

這個指令用于對棧頂?shù)膬蓚€值進行減法運算并將結果推送到棧中。

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

同樣的加減乘除取余數(shù)的字節(jié)碼如下所示:

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

這個指令用于比較棧頂?shù)膬蓚€值,并且將比較得到的結果壓入棧中,這個字節(jié)碼后面后一個字節(jié)的參數(shù),表示小于大于不等于等等比較符號。例如:

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

將棧頂元素彈出作為返回值。

BUILD_LIST

這個指令用于創(chuàng)建一個列表。例如:

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

這條字節(jié)碼指令有一個參數(shù)表示??臻g當中列表元素的個數(shù),在上面的例子當中這個參數(shù)是 4 。

BUILD_TUPLE

這個指令用于創(chuàng)建一個元組。例如:

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

同樣的這個字節(jié)碼也有一個參數(shù),表示創(chuàng)建元組的元素個數(shù)。

BUILD_MAP

這個指令用于創(chuàng)建一個字典。例如:

BUILD_SET

和 list 和 tuple 一樣,這條指令是用于創(chuàng)建一個集合對象,同樣的這條指令也有一個參數(shù)表示用于創(chuàng)建集合的元素的個數(shù)。

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

這條指令是用于創(chuàng)建一個字典對象,同樣的這條指令也有一個參數(shù),表示字典當中元素的個數(shù)。

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

從字節(jié)碼角度分析裝飾器的原理

如果你是一個 pythoner 那么你肯定或多或少聽說過裝飾器,這是一個 python 的語法糖我們可以用它來做很多有趣的事情,比如在不修改源代碼的基礎之上給函數(shù)附加一些功能,比如說計算時間。

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

在上面的代碼當中我們實現(xiàn)了一個計算斐波拉契數(shù)列的函數(shù),除此之外還寫了一個 eval_time 函數(shù)用于計算函數(shù)執(zhí)行的時間,現(xiàn)在調用函數(shù) fib(10),程序的輸出如下所示:

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

可以看到實現(xiàn)了我們想要的效果。

現(xiàn)在我們使用一個更加簡單的例子來模擬上面的代碼結構,方便我們對上面函數(shù)執(zhí)行的過程進行分析:

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

上面的 dis 函數(shù)的輸出對應代碼的字節(jié)碼如下所示:

  2           0 LOAD_CONST               0 (<code object decorator at 0x108068d40, file "<dis>", line 2>)
              2 LOAD_CONST               1 ('decorator')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (decorator)
 
  6           8 LOAD_NAME                0 (decorator)
 
  7          10 LOAD_CONST               2 (<code object fib at 0x1075c1710, file "<dis>", line 6>)
             12 LOAD_CONST               3 ('fib')
             14 MAKE_FUNCTION            0
             16 CALL_FUNCTION            1
             18 STORE_NAME               1 (fib)
             20 LOAD_CONST               4 (None)
             22 RETURN_VALUE
 
Disassembly of <code object decorator at 0x108068d40, file "<dis>", line 2>:
  3           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('Hello')
              4 CALL_FUNCTION            1
              6 POP_TOP
 
  4           8 LOAD_FAST                0 (func)
             10 RETURN_VALUE
 
Disassembly of <code object fib at 0x1075c1710, file "<dis>", line 6>:
  8           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE

執(zhí)行第一條指令 LOAD_CONST,這條指令主要是加載一個 code object 對象,這個對象里面主要是包含函數(shù) decorator 的字節(jié)碼,主要是上面字節(jié)碼的第二塊內容。在執(zhí)行完這條字節(jié)碼之后??臻g如下所示:

執(zhí)行完第二條指令 LOAD_CONST 之后,會將字符串 decorator 加載進入??臻g當中。

執(zhí)行第三條指令 MAKE_FUNCTION,這條字節(jié)碼的作用是在虛擬機內部創(chuàng)建一個函數(shù),函數(shù)的名稱為 decorator,函數(shù)對應的字節(jié)碼則是在先前壓入??臻g當中的 code object 對象,這條指令還會將創(chuàng)建好的函數(shù)對象壓入棧中。

STORE_NAME,條字節(jié)碼會將棧頂?shù)脑貜棾?,并且?co_names[oparg] 指向這個對象,在上面的字節(jié)碼當中 co_names[oparg] 就是 decorator 。

LOAD_NAME,這條字節(jié)碼就是將 co_names[oparg] 對應的名字指向的對象重新加載進入??臻g當中,也就是上面的 decorator 函數(shù)加入進行??臻g當中。

接下來的三條字節(jié)碼 LOAD_CONST,LOAD_CONST 和 MAKE_FUNCTION,在執(zhí)行這三條字節(jié)碼之后,??臻g如下所示:

接下來的一條指令非常重要,這條指令便是裝飾器的核心原理,CALL_FUNCTION 這條指令有一個參數(shù) i,在上面的字節(jié)碼當中為 1,也就是說從棧頂開始的前 i 個元素都是函數(shù)參數(shù),調用的函數(shù)在??臻g的位置為 i + 1 (從棧頂往下數(shù)),那么在上面的情況下就是說調用 decorator 函數(shù),并且將 fib 函數(shù)作為 decorator 函數(shù)的參數(shù),decorator 函數(shù)的返回值再壓入棧頂。在上面的代碼當中 decorator 函數(shù)返回值也是一個函數(shù),也就是 decorator 函數(shù)的參數(shù),即 fib 函數(shù)。

接下來便是 STORE_NAME 字節(jié)碼,這條字節(jié)碼的含義我們在前面已經(jīng)說過了,就是將棧頂元素彈出,保存到 co_names[oparg] 指向的對象當中,在上面的代碼當中也就是將棧頂?shù)膶ο蟊4娴?fib 當中。棧頂元素 fib 函數(shù)是調用函數(shù) decorator 的返回值。

看到這里就能夠理解了原來裝飾器的最根本的原理不就是函數(shù)調用嘛,比如我們最前面的用于計算函數(shù)執(zhí)行時間的裝飾器的原理就是:

fib = eval_time(fib)

將 fib 函數(shù)作為 eval_time 函數(shù)的參數(shù),再將這個函數(shù)的返回值保存到 fib 當中,當然這個對象必須是可調用的,不然后面使用 fib() 就會保存,我們可以使用下面的代碼來驗證這個效果。

def decorator(func):
    return func()
 
 
@decorator
def demo():
    return "function demo return string : Demo"
 
print(demo)

執(zhí)行上面的程序結果為:

function demo return string : Demo

可以看到 demo 已經(jīng)變成了一個字符串對象而不再是一個函數(shù)了,因為 demo = decorator(demo),而在函數(shù) decorator 當中返回值是 demo 函數(shù)自己的返回值,因此才打印了字符串。

總結

在本篇文章當中主要給大家介紹了 python 當中一些基礎的字節(jié)碼對應的含義以及示例代碼,本篇文章最重要的便是從字節(jié)碼的角度解釋了裝飾器的本質原理,這對我們以后使用裝飾器非常有幫助,可以靈活的控制和了解裝飾器其中發(fā)生的故事。

以上就是Python虛擬機字節(jié)碼教程之裝飾器實現(xiàn)詳解的詳細內容,更多關于Python字節(jié)碼 裝飾器的資料請關注腳本之家其它相關文章!

相關文章

  • 基于Python+Pygame實現(xiàn)變異狗大戰(zhàn)游戲

    基于Python+Pygame實現(xiàn)變異狗大戰(zhàn)游戲

    只有你想不到,沒有我找不到寫不了的好游戲!這篇文章就來和大家分享一下如何基于Python+Pygame實現(xiàn)變異狗大戰(zhàn)游戲,感興趣的可以了解一下
    2023-03-03
  • django配置使用asgi的實現(xiàn)步驟

    django配置使用asgi的實現(xiàn)步驟

    本文主要介紹了django配置使用asgi的實現(xiàn)步驟,支持 ASGI 協(xié)議能處理傳統(tǒng)HTTP請求,也能支持實時WebSocket通信,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • python殺死一個線程的方法

    python殺死一個線程的方法

    由于python線程沒有提供abort方法,所以我們需要自己想辦法解決此問題,面對這一問題,小編幫大家解決phthon殺死一個線程的方法,需要的朋友一起來學習吧
    2015-09-09
  • 解決安裝pyqt5之后無法打開spyder的問題

    解決安裝pyqt5之后無法打開spyder的問題

    今天小編就為大家分享一篇解決安裝pyqt5之后無法打開spyder的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • django-初始配置(純手寫)詳解

    django-初始配置(純手寫)詳解

    這篇文章主要介紹了django-初始配置(純手寫)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-07-07
  • python3新特性函數(shù)注釋Function Annotations用法分析

    python3新特性函數(shù)注釋Function Annotations用法分析

    這篇文章主要介紹了python3新特性函數(shù)注釋Function Annotations用法,結合實例形式分析了Python3函數(shù)注釋的定義方法與使用技巧,需要的朋友可以參考下
    2016-07-07
  • python檢測服務器端口代碼實例

    python檢測服務器端口代碼實例

    這篇文章主要介紹了python檢測服務器端口代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • 2020年10款優(yōu)秀的Python第三方庫,看看有你中意的嗎?

    2020年10款優(yōu)秀的Python第三方庫,看看有你中意的嗎?

    2020已經(jīng)過去,在過去的一年里,又有非常多優(yōu)秀的Python庫涌現(xiàn)出來。相對于numpy、TensorFlow、pandas這些已經(jīng)經(jīng)過多年維護、迭代,對于大多數(shù)Python開發(fā)者耳熟能詳?shù)膸觳煌?/div> 2021-01-01
  • 使用Python實現(xiàn)Office文檔(Word/Excel/PowerPoint)批量轉換為PDF

    使用Python實現(xiàn)Office文檔(Word/Excel/PowerPoint)批量轉換為PDF

    在處理不同格式的Office文檔(如Word、Excel和PowerPoint)時,將其轉換為PDF格式是常見的需求,本文就跟隨小編來看看如何使用Python將Word/Excel/PowerPoint批量轉換為PDF吧
    2024-10-10
  • 如何將yolo格式轉化為voc格式:txt轉xml(親測有效)

    如何將yolo格式轉化為voc格式:txt轉xml(親測有效)

    這篇文章主要介紹了如何將yolo格式轉化為voc格式:txt轉xml,親測有效,可以使用,本文通過圖文并茂的形式給大家介紹的非常詳細,感興趣的朋友參考下吧
    2023-12-12

最新評論

交城县| 郁南县| 郴州市| 屯留县| 镇康县| 奉贤区| 新宁县| 莱州市| 八宿县| 宕昌县| 兰坪| 温州市| 青阳县| 乌苏市| 榆树市| 古田县| 沭阳县| 吉木萨尔县| 信阳市| 扶沟县| 新沂市| 康马县| 珠海市| 娄烦县| 浦县| 莱阳市| 湘潭市| 宾阳县| 库尔勒市| 新余市| 民勤县| 平湖市| 来凤县| 霍林郭勒市| 庆安县| 全南县| 礼泉县| 四平市| 江山市| 锦州市| 巨鹿县|