欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解Python虛擬機(jī)中的Code?obejct

 更新時(shí)間:2023年04月02日 09:48:29   作者:一無是處的研究僧  
在本篇文章當(dāng)中主要給大家深入介紹在?cpython?當(dāng)中非常重要的一個(gè)數(shù)據(jù)結(jié)構(gòu)?code?object!?我們簡單介紹了一下在?code?object?當(dāng)中有哪些字段以及這些字段的簡單含義,在本篇文章當(dāng)中將會舉一些例子以便更加深入理解這些字段

在本篇文章當(dāng)中主要給大家深入介紹在 cpython 當(dāng)中非常重要的一個(gè)數(shù)據(jù)結(jié)構(gòu) code object! 在上一篇文章 深入理解 python 虛擬機(jī):pyc 文件結(jié)構(gòu) ,我們簡單介紹了一下在 code object 當(dāng)中有哪些字段以及這些字段的簡單含義,在本篇文章當(dāng)中將會舉一些例子以便更加深入理解這些字段。

Code Object 數(shù)據(jù)結(jié)構(gòu)

typedef struct {
    PyObject_HEAD
    int co_argcount;		/* #arguments, except *args */
    int co_kwonlyargcount;	/* #keyword only arguments */
    int co_nlocals;		/* #local variables */
    int co_stacksize;		/* #entries needed for evaluation stack */
    int co_flags;		/* CO_..., see below */
    PyObject *co_code;		/* instruction opcodes */
    PyObject *co_consts;	/* list (constants used) */
    PyObject *co_names;		/* list of strings (names used) */
    PyObject *co_varnames;	/* tuple of strings (local variable names) */
    PyObject *co_freevars;	/* tuple of strings (free variable names) */
    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
    /* The rest aren't used in either hash or comparisons, except for
       co_name (used in both) and co_firstlineno (used only in
       comparisons).  This is done to preserve the name and line number
       for tracebacks and debuggers; otherwise, constant de-duplication
       would collapse identical functions/lambdas defined on different lines.
    */
    unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
    PyObject *co_filename;	/* unicode (where it was loaded from) */
    PyObject *co_name;		/* unicode (name, for reference) */
    int co_firstlineno;		/* first source line number */
    PyObject *co_lnotab;	/* string (encoding addr<->lineno mapping) See
				   Objects/lnotab_notes.txt for details. */
    void *co_zombieframe;     /* for optimization only (see frameobject.c) */
    PyObject *co_weakreflist;   /* to support weakrefs to code objects */
} PyCodeObject;

下面是 code object 當(dāng)中各個(gè)字段的作用:

  • 首先需要了解一下代碼塊這個(gè)概念,所謂代碼塊就是一個(gè)小的 python 代碼,被當(dāng)做一個(gè)小的單元整體執(zhí)行。在 python 當(dāng)中常見的代碼塊塊有:函數(shù)體、類的定義、一個(gè)模塊。
  • argcount,這個(gè)表示一個(gè)代碼塊的參數(shù)個(gè)數(shù),這個(gè)參數(shù)只對函數(shù)體代碼塊有用,因?yàn)楹瘮?shù)可能會有參數(shù),比如上面的 pycdemo.py 是一個(gè)模塊而不是一個(gè)函數(shù),因此這個(gè)參數(shù)對應(yīng)的值為 0 。
  • co_code,這個(gè)對象的具體內(nèi)容就是一個(gè)字節(jié)序列,存儲真實(shí)的 python 字節(jié)碼,主要是用于 python 虛擬機(jī)執(zhí)行的,在本篇文章當(dāng)中暫時(shí)不詳細(xì)分析。
  • co_consts,這個(gè)字段是一個(gè)列表類型的字段,主要是包含一些字符串常量和數(shù)值常量,比如上面的 "__main__" 和 100 。
  • co_filename,這個(gè)字段的含義就是對應(yīng)的源文件的文件名。
  • co_firstlineno,這個(gè)字段的含義為在 python 源文件當(dāng)中第一行代碼出現(xiàn)的行數(shù),這個(gè)字段在進(jìn)行調(diào)試的時(shí)候非常重要。
  • co_flags,這個(gè)字段的主要含義就是標(biāo)識這個(gè) code object 的類型。0x0080 表示這個(gè) block 是一個(gè)協(xié)程,0x0010 表示這個(gè) code object 是嵌套的等等。
  • co_lnotab,這個(gè)字段的含義主要是用于計(jì)算每個(gè)字節(jié)碼指令對應(yīng)的源代碼行數(shù)。
  • co_varnames,這個(gè)字段的主要含義是表示在一個(gè) code object 本地定義的一個(gè)名字。
  • co_names,和 co_varnames 相反,表示非本地定義但是在 code object 當(dāng)中使用的名字。
  • co_nlocals,這個(gè)字段表示在一個(gè) code object 當(dāng)中本地使用的變量個(gè)數(shù)。
  • co_stackszie,因?yàn)?python 虛擬機(jī)是一個(gè)棧式計(jì)算機(jī),這個(gè)參數(shù)的值表示這個(gè)棧需要的最大的值。
  • co_cellvars,co_freevars,這兩個(gè)字段主要和嵌套函數(shù)和函數(shù)閉包有關(guān),我們在后續(xù)的文章當(dāng)中將詳細(xì)解釋這個(gè)字段。

CodeObject 詳細(xì)分析

現(xiàn)在我們使用一些實(shí)際的例子來分析具體的 code object 。

import dis
import binascii
import types

d = 10


def test_co01(c):
    a = 1
    b = 2
    return a + b + c + d

在前面的文章當(dāng)中我們提到過一個(gè)函數(shù)是包括一個(gè) code object 對象,test_co01 的 code object 對象的輸出結(jié)果(完整代碼見co01)如下所示:

code
   argcount 1
   nlocals 3
   stacksize 2
   flags 0043 0x43
   code b'6401007d01006402007d02007c01007c0200177c0000177400001753'
  9           0 LOAD_CONST               1 (1)
              3 STORE_FAST               1 (a)

 10           6 LOAD_CONST               2 (2)
              9 STORE_FAST               2 (b)

 11          12 LOAD_FAST                1 (a)
             15 LOAD_FAST                2 (b)
             18 BINARY_ADD
             19 LOAD_FAST                0 (c)
             22 BINARY_ADD
             23 LOAD_GLOBAL              0 (d)
             26 BINARY_ADD
             27 RETURN_VALUE
   consts
      None
      1
      2
   names ('d',)
   varnames ('c', 'a', 'b')
   freevars ()
   cellvars ()
   filename '/tmp/pycharm_project_396/co01.py'
   name 'test_co01'
   firstlineno 8
   lnotab b'000106010601'
  • 字段 argcount 的值等于 1,說明函數(shù)有一個(gè)參數(shù),這個(gè)函數(shù) test_co01 有一個(gè)參數(shù) c 是相互對應(yīng)的。
  • 字段 nlocals 的值等于 3,說明在函數(shù) test_co01 當(dāng)中一個(gè)一共實(shí)現(xiàn)了三個(gè)函數(shù)本地變量 a, b, c 。
  • 字段 names,對應(yīng)代碼代碼當(dāng)中的 co_names,根據(jù)前面的定義就是 d 這個(gè)全局變量在函數(shù) test_co01 當(dāng)中使用,但是卻沒有在函數(shù)當(dāng)中定義了。
  • 字段 varnames,這個(gè)就表示在本地定義使用的變量了,在函數(shù) test_co01 當(dāng)中主要有三個(gè)變量 a, b, c 。
  • 字段 filename,就是 python 文件的地址了。
  • 字段 firstlineno 說明函數(shù)的第一行出現(xiàn)在對應(yīng) python 代碼的 第 8 行。

Flags 字段詳細(xì)分析

我們具體使用 python3.5 的源代碼進(jìn)行分析,在 cpython 虛擬機(jī)的具體實(shí)現(xiàn)如下所示(Include/code.h):

/* Masks for co_flags above */
#define CO_OPTIMIZED	0x0001
#define CO_NEWLOCALS	0x0002
#define CO_VARARGS	0x0004
#define CO_VARKEYWORDS	0x0008
#define CO_NESTED       0x0010
#define CO_GENERATOR    0x0020
/* The CO_NOFREE flag is set if there are no free or cell variables.
   This information is redundant, but it allows a single flag test
   to determine whether there is any extra work to be done when the
   call frame it setup.
*/
#define CO_NOFREE       0x0040

/* The CO_COROUTINE flag is set for coroutine functions (defined with
   ``async def`` keywords) */
#define CO_COROUTINE            0x0080
#define CO_ITERABLE_COROUTINE   0x0100

如果 flags 字段和上面的各個(gè)宏定義進(jìn)行 & 運(yùn)算,如果得到的結(jié)果大于 0,則說明符合對應(yīng)的條件。

上面的宏定義的含義如下所示:

  • CO_OPTIMIZED,這個(gè)字段表示 code object 是被優(yōu)化過的,使用函數(shù)本地定義的變量。
  • CO_NEWLOCALS,這個(gè)字段的含義為當(dāng)這個(gè) code object 的代碼被執(zhí)行的時(shí)候會給棧幀當(dāng)中的 f_locals 對象創(chuàng)建一個(gè) dict 對象。
  • CO_VARARGS,表示這個(gè) code object 對象是否含有位置參數(shù)。
  • CO_VARKEYWORDS,表示這個(gè) code object 是否含有關(guān)鍵字參數(shù)。
  • CO_NESTED,表示這個(gè) code object 是一個(gè)嵌套函數(shù)。
  • CO_GENERATOR,表示這個(gè) code object 是一個(gè)生成器。
  • CO_COROUTINE,表示這個(gè) code object 是一個(gè)協(xié)程函數(shù)。
  • CO_ITERABLE_COROUTINE,表示 code object 是一個(gè)可迭代的協(xié)程函數(shù)。
  • CO_NOFREE,這個(gè)表示沒有 freevars 和 cellvars,即沒有函數(shù)閉包。

現(xiàn)在再分析一下前面的函數(shù) test_co01 的 flags,他對應(yīng)的值等于 0x43,則說明這個(gè)函數(shù)滿足三個(gè)特性分別是 CO_NEWLOCALS,CO_OPTIMIZED 和 CO_NOFREE。

freevars & cellvars

我們使用下面的函數(shù)來對這兩個(gè)字段進(jìn)行分析:

def test_co02():
    a = 1
    b = 2

    def g():
        return a + b
    return a + b + g()

上面的函數(shù)的信息如下所示(完整代碼見co02):

code
   argcount 0
   nlocals 1
   stacksize 3
   flags 0003 0x3
   code
      b'640100890000640200890100870000870100660200640300640400860000'
      b'7d0000880000880100177c00008300001753'
 15           0 LOAD_CONST               1 (1)
              3 STORE_DEREF              0 (a)

 16           6 LOAD_CONST               2 (2)
              9 STORE_DEREF              1 (b)

 18          12 LOAD_CLOSURE             0 (a)
             15 LOAD_CLOSURE             1 (b)
             18 BUILD_TUPLE              2
             21 LOAD_CONST               3 (<code object g at 0x7f133ff496f0, file "/tmp/pycharm_project_396/co01.py", line 18>)
             24 LOAD_CONST               4 ('test_co02.<locals>.g')
             27 MAKE_CLOSURE             0
             30 STORE_FAST               0 (g)

 20          33 LOAD_DEREF               0 (a)
             36 LOAD_DEREF               1 (b)
             39 BINARY_ADD
             40 LOAD_FAST                0 (g)
             43 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
             46 BINARY_ADD
             47 RETURN_VALUE
   consts
      None
      1
      2
      code
         argcount 0
         nlocals 0
         stacksize 2
         flags 0013 0x13
         code b'8800008801001753'
 19           0 LOAD_DEREF               0 (a)
              3 LOAD_DEREF               1 (b)
              6 BINARY_ADD
              7 RETURN_VALUE
         consts
            None
         names ()
         varnames ()
         freevars ('a', 'b')
         cellvars ()
         filename '/tmp/pycharm_project_396/co01.py'
         name 'g'
         firstlineno 18
         lnotab b'0001'
      'test_co02.<locals>.g'
   names ()
   varnames ('g',)
   freevars ()
   cellvars ('a', 'b')
   filename '/tmp/pycharm_project_396/co01.py'
   name 'test_co02'
   firstlineno 14
   lnotab b'0001060106021502'

從上面的輸出我們可以看到的是,函數(shù) test_co02 的 cellvars 為 ('a', 'b'),函數(shù) g 的 freevars 為 ('a', 'b'),cellvars 表示在其他函數(shù)當(dāng)中會使用本地定義的變量,freevars 表示本地會使用其他函數(shù)定義的變量。

再來分析一下函數(shù) test_co02 的 flags,他的 flags 等于 0x3 因?yàn)橛虚]包的存在因此 flags 不會存在 CO_NOFREE,也就是少了值 0x0040 。

stacksize

這個(gè)字段存儲的是在函數(shù)在被虛擬機(jī)執(zhí)行的時(shí)候所需要的最大的棧空間的大小,這也是一種優(yōu)化手段,因?yàn)樵谥浪枰淖畲蟮臈?臻g,所以可以在函數(shù)執(zhí)行的時(shí)候直接分配指定大小的空間不需要在函數(shù)執(zhí)行的時(shí)候再去重新擴(kuò)容。

def test_stack():
    a = 1
    b = 2
    return a + b

上面的代碼相關(guān)字節(jié)碼等信息如下所示:

code
   argcount 0
   nlocals 2
   stacksize 2
   flags 0043 0x43
   code b'6401007d00006402007d01007c00007c01001753'
   #					  字節(jié)碼指令		 # 字節(jié)碼指令參數(shù) # 參數(shù)對應(yīng)的值
 24           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

 25           6 LOAD_CONST               2 (2)
              9 STORE_FAST               1 (b)

 26          12 LOAD_FAST                0 (a)
             15 LOAD_FAST                1 (b)
             18 BINARY_ADD
             19 RETURN_VALUE
   consts
      None # 下標(biāo)等于 0 的常量
      1 	 # 下標(biāo)等于 1 的常量
      2		 # 下標(biāo)等于 2 的常量
   names ()
   varnames ('a', 'b')
   freevars ()
   cellvars ()

我們現(xiàn)在來模擬一下執(zhí)行過程,在模擬之前我們首先來了解一下上面幾條字節(jié)碼的作用:

LOAD_CONST,將常量表當(dāng)中的下標(biāo)等于 i 個(gè)對象加載到棧當(dāng)中,對應(yīng)上面的代碼 LOAD_CONST 的參數(shù) i = 1。因此加載測常量等于 1 。因此現(xiàn)在??臻g如下所示:

STORE_FAST,將棧頂元素彈出并且保存到 co_varnames 對應(yīng)的下標(biāo)當(dāng)中,根據(jù)上面的字節(jié)碼參數(shù)等于 0 ,因此將 1 保存到 co_varnames[0] 對應(yīng)的對象當(dāng)中。

LOAD_CONST,將下標(biāo)等于 2 的常量加載進(jìn)入棧中。

STORE_FAST,將棧頂元素彈出,并且保存到 varnames 下標(biāo)為 1 的對象。

LOAD_FAST,是取出 co_varnames 對應(yīng)下標(biāo)的數(shù)據(jù),并且將其壓入棧中。我們直接連續(xù)執(zhí)行兩個(gè) LOAD_FAST 之后??臻g的布局如下:

BINARY_ADD,這個(gè)字節(jié)碼指令是將棧空間的兩個(gè)棧頂元素彈出,然后將兩個(gè)數(shù)據(jù)進(jìn)行相加操作,然后將相加得到的結(jié)果重新壓入棧中。

RETURN_VALUE,將棧頂元素彈出并且作為返回值返回。

從上面的整個(gè)執(zhí)行過程來看整個(gè)??臻g使用的最大的空間長度為 2 ,因此 stacksize = 2 。

總結(jié)

在本篇文章當(dāng)中主要分析了一些 code obejct 當(dāng)中比較重要的字段,code object 是 cpython 虛擬機(jī)當(dāng)中一個(gè)比較重要的數(shù)據(jù)結(jié)構(gòu),深入的去理解這里面的字段對于我們理解 python 虛擬機(jī)非常有幫助。

以上就是深入理解Python虛擬機(jī)中的Code obejct的詳細(xì)內(nèi)容,更多關(guān)于Python虛擬機(jī)Code obejct的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Django 創(chuàng)建后臺,配置sqlite3教程

    Django 創(chuàng)建后臺,配置sqlite3教程

    今天小編就為大家分享一篇Django 創(chuàng)建后臺,配置sqlite3教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • 使用Python腳本對GiteePages進(jìn)行一鍵部署的使用說明

    使用Python腳本對GiteePages進(jìn)行一鍵部署的使用說明

    剛好之前有了解過python的自動化,就想著自動化腳本,百度一搜還真有類似的文章。今天就給大家分享下使用Python腳本對GiteePages進(jìn)行一鍵部署的使用說明,感興趣的朋友一起看看吧
    2021-05-05
  • Python數(shù)據(jù)分析?Pandas?Series對象操作

    Python數(shù)據(jù)分析?Pandas?Series對象操作

    這篇文章主要介紹了Python數(shù)據(jù)分析之Pandas?Series對象,文章基于python的相關(guān)資料展開詳細(xì)內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • python實(shí)現(xiàn)數(shù)字炸彈游戲

    python實(shí)現(xiàn)數(shù)字炸彈游戲

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)數(shù)字炸彈游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • python 獲取當(dāng)前目錄下的文件目錄和文件名實(shí)例代碼詳解

    python 獲取當(dāng)前目錄下的文件目錄和文件名實(shí)例代碼詳解

    這篇文章主要介紹了python 獲取當(dāng)前目錄下的文件目錄和文件名實(shí)例代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • python獲取指定日期范圍內(nèi)的每一天,每個(gè)月,每季度的方法

    python獲取指定日期范圍內(nèi)的每一天,每個(gè)月,每季度的方法

    這篇文章主要介紹了python獲取指定日期范圍內(nèi)的每一天,每個(gè)月,每季度的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 安裝2019Pycharm最新版本的教程詳解

    安裝2019Pycharm最新版本的教程詳解

    這篇文章主要介紹了安裝2019Pycharm最新版本的教程詳解,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Python數(shù)據(jù)可視化Pyecharts庫的使用教程

    Python數(shù)據(jù)可視化Pyecharts庫的使用教程

    pyecharts是一個(gè)用于生成echarts圖表的類庫。echarts是百度開源的一個(gè)數(shù)據(jù)可視化庫,用echarts生成的圖可視化效果非常棒。使用pyechart庫可以在python中生成echarts數(shù)據(jù)圖。本文將詳細(xì)介紹一下Pyecharts庫的使用,需要的可以參考一下
    2022-02-02
  • Anaconda環(huán)境GDAL庫基于whl文件的配置方法

    Anaconda環(huán)境GDAL庫基于whl文件的配置方法

    這篇文章主要介紹了Anaconda環(huán)境GDAL庫基于whl文件的配置方法,我們介紹了基于conda?install命令直接聯(lián)網(wǎng)安裝GDAL庫的方法,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • Python 實(shí)現(xiàn)Windows開機(jī)運(yùn)行某軟件的方法

    Python 實(shí)現(xiàn)Windows開機(jī)運(yùn)行某軟件的方法

    今天小編就為大家分享一篇Python 實(shí)現(xiàn)Windows開機(jī)運(yùn)行某軟件的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10

最新評論