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

Python編譯結(jié)果之code對(duì)象與pyc文件詳解

 更新時(shí)間:2021年10月19日 15:15:31   作者:efeics  
今天小編就為大家分享一篇對(duì)Python編譯結(jié)果之code對(duì)象與pyc文件的詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

1、Python程序執(zhí)行過(guò)程

與java類似,Python將.py編譯為字節(jié)碼,然后通過(guò)虛擬機(jī)執(zhí)行。編譯過(guò)程與虛擬機(jī)執(zhí)行過(guò)程均在python25.dll中。Python虛擬機(jī)比java更抽象,離底層更遠(yuǎn)。

編譯過(guò)程不僅生成字節(jié)碼,還要包含常量、變量、占用棧的空間等,Pyton中編譯過(guò)程生成code對(duì)象PyCodeObject。將PyCodeObject寫入二進(jìn)制文件,即.pyc。


有必要?jiǎng)t寫入A.pyc指的是該.py是否只運(yùn)行一次,如果import的模塊,肯定會(huì)生成.pyc。

2、PyCodeObject對(duì)象與.pyc文件

Python解釋器將.py程序編譯為PyCodeObject對(duì)象,具體過(guò)程與編譯原理類似。

typedef struct {
    PyObject_HEAD
    int co_argcount;		// Code Block的參數(shù)的個(gè)數(shù),比如說(shuō)一個(gè)函數(shù)的參數(shù)
    int co_nlocals;			// Code Block中局部變量的個(gè)數(shù)
    int co_stacksize;		// 執(zhí)行該段Code Block需要的??臻g
    int co_flags;			// N/A
    PyObject *co_code;		// Code Block編譯所得的byte code,以PyStringObject的形式存在
    PyObject *co_consts;	// PyTupleObject對(duì)象,保存Code Block中的常量
    PyObject *co_names;		// PyTupleObject對(duì)象,保存Code Block中的所有符號(hào)
    PyObject *co_varnames;	// Code Block中局部變量名集合
    PyObject *co_freevars;	// 實(shí)現(xiàn)閉包所需東西
    PyObject *co_cellvars;  // Code Block內(nèi)部嵌套函數(shù)所引用的局部變量名集合
    PyObject *co_filename;	// Code Block所對(duì)應(yīng)的.py文件的完整路徑
    PyObject *co_name;		// Code Block的名字,通常是函數(shù)名或類名
    int co_firstlineno;		// Code Block在對(duì)應(yīng)的.py文件中的起始行
    PyObject *co_lnotab;	// byte code與.py文件中source code行號(hào)的對(duì)應(yīng)關(guān)系,以PyStringObject的形式存在
    void *co_zombieframe;
    PyObject *co_weakreflist;
} PyCodeObject;

一個(gè)Code Block生成一個(gè)PyCodeObject,進(jìn)入一個(gè)名字空間成為進(jìn)入一個(gè)Code Block。如下.py文件編譯完成后會(huì)生成三個(gè)PyCodeObject,一個(gè)對(duì)應(yīng)整個(gè).py文件一個(gè)對(duì)應(yīng)Class A,一個(gè)對(duì)應(yīng)def Fun。實(shí)際這三個(gè)code對(duì)象是嵌套的,后兩個(gè)code對(duì)象位于第一個(gè)code對(duì)象的co_consts屬性中。其實(shí),字節(jié)碼位于co_code中。

class A:
	pass
def Fun():
	pass
a = A()
Fun()

pyc文件包括三部分:

(1)四字節(jié)的Magic int,表示pyc版本信息

(2)四字節(jié)的int,是pyc產(chǎn)生時(shí)間,若與py文件時(shí)間不同會(huì)重新生成

(3)序列化了的PyCodeObject對(duì)象。

3、pyc文件的生成

寫入pyc文件的函數(shù)包括以下幾個(gè)步驟:

PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION);	// 寫入版本信息
PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);			// 寫入時(shí)間信息
PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);	// 寫入PyCodeObject對(duì)象

關(guān)鍵在于code對(duì)象的寫入:

{
    WFILE wf;
    wf.fp = fp;
	……
    w_object(x, &wf);
}

用到了一個(gè)WFILE結(jié)構(gòu)體,可以認(rèn)為是對(duì)FILE *fp 的一個(gè)封裝:

typedef struct {
    FILE *fp;
    int error;
    int depth;
    PyObject *strings; // 存儲(chǔ)字符串,寫入時(shí)以dict形式,讀出時(shí)以list形式
} WFILE;

關(guān)鍵在于w_object()函數(shù):

static void w_object(PyObject *v, WFILE *p){
	if (v == NULL)	……
	else if (PyInt_CheckExact(v)) ……
	else if (PyFloat_CheckExact(v)) ……
	else if (PyString_CheckExact(v)) ……
	else if (PyList_CheckExact(v)) ……
}

w_code實(shí)質(zhì)為根據(jù)不同的對(duì)象類型選取不同的策略,例如tuple對(duì)象:

    else if (PyTuple_CheckExact(v)) {
        w_byte(TYPE_TUPLE, p);
        n = PyTuple_Size(v);
        W_SIZE(n, p);
        for (i = 0; i < n; i++) 
            w_object(PyTuple_GET_ITEM(v, i), p);

而所有類型最終可分解為寫入數(shù)值與寫入字符串兩種操作,涉及以下幾部分:

#define w_byte(c, p) putc((c), (p)->fp)	// 用于寫入類型
static void w_long(long x, WFILE *p){	// 用于寫入數(shù)字	
    w_byte((char)( x      & 0xff), p);	// 實(shí)質(zhì)為用四個(gè)字節(jié)存儲(chǔ)一個(gè)數(shù)字
    w_byte((char)((x>> 8) & 0xff), p);
    w_byte((char)((x>>16) & 0xff), p);
    w_byte((char)((x>>24) & 0xff), p);
}
static void w_string(char *s, int n, WFILE *p){	//用于寫入字符串
    fwrite(s, 1, n, p->fp);
}

由于序列化寫入文件后丟失了結(jié)構(gòu)信息,故寫入每個(gè)對(duì)象時(shí)寫入類型信息w_byte:

#define TYPE_INT                'i'
#define TYPE_LIST               '['
#define TYPE_DICT               '{'
#define TYPE_CODE               'c'

由于Python皆對(duì)象,w_object(PyObject*)便可針對(duì)不同類型選取不同寫入方法,不斷細(xì)分,最終分解為PyInt_Object或PyString_Object,利用w_long或w_string寫入。

數(shù)字比較簡(jiǎn)單:

else if (PyInt_CheckExact(v)) {
    w_byte(TYPE_INT, p);
    w_long(x, p);
}

字符串則比較復(fù)雜:

 else if (PyString_CheckExact(v)) {
        if (p->strings && PyString_CHECK_INTERNED(v)) {
            PyObject *o = PyDict_GetItem(p->strings, v);	// 獲取在strings中的序號(hào)
            if (o) {			// inter對(duì)象的非首次寫入
                long w = PyInt_AsLong(o);
                w_byte(TYPE_STRINGREF, p);
                w_long(w, p);
                goto exit;
            }
            else {				// intern對(duì)象的首次寫入
                int ok;
                ok = o && PyDict_SetItem(p->strings, v, o) >= 0;
                Py_XDECREF(o);
                w_byte(TYPE_INTERNED, p);
            }
        }
        else {					// 寫入普通string
            w_byte(TYPE_STRING, p);
        }
        n = PyString_GET_SIZE(v);
        W_SIZE(n, p);
        w_string(PyString_AS_STRING(v), n, p);
    }		

(1)若寫入普通字符串,寫入字符串類型信息"S",然后寫入字符串長(zhǎng)度及string值。

(2)若寫入inter字符串,先到WFILE的strings中查找:

(a)若找到,則寫入引用類型信息"R",然后寫入序號(hào)

(b)若未找到,創(chuàng)建對(duì)象放入strings,并寫入intern類型信息"t",然后寫入字符串長(zhǎng)度及string值。
若依次寫入"efei"、"snow"、"efei",則會(huì)如下:


從pyc文件讀入時(shí),依靠list,那么序號(hào)就可以利用上了。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Python使用turtle繪制有趣的龍年祝福動(dòng)畫

    Python使用turtle繪制有趣的龍年祝福動(dòng)畫

    這篇文章主要介紹了Python的內(nèi)置庫(kù)——小海龜(turtle),它是一個(gè)非常實(shí)用的繪畫工具,不僅可以幫助我們繪制圖形,還能讓我們查看整個(gè)繪畫過(guò)程,下面我們就來(lái)看看如何使用turtle繪制有趣的龍年祝福動(dòng)畫吧
    2024-01-01
  • Python正則表達(dá)式的小練習(xí)分享

    Python正則表達(dá)式的小練習(xí)分享

    為了讓大家更進(jìn)一步了解Python中的正則表達(dá)式使用,本文為大家分享了三個(gè)正則表達(dá)式使用小練習(xí),感興趣的小伙伴可以學(xué)習(xí)一下
    2022-04-04
  • 分享vim python縮進(jìn)等一些配置

    分享vim python縮進(jìn)等一些配置

    本篇文章給大家分享了vim python縮進(jìn)等一些配置的相關(guān)知識(shí)點(diǎn),有需要的朋友可以參考下。
    2018-07-07
  • Python計(jì)算公交發(fā)車時(shí)間的完整代碼

    Python計(jì)算公交發(fā)車時(shí)間的完整代碼

    這篇文章主要介紹了Python計(jì)算公交發(fā)車時(shí)間的完整代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 詳解python中的json和字典dict

    詳解python中的json和字典dict

    python中,json和dict非常類似,都是key-value的形式,而且json、dict也可以非常方便的通過(guò)dumps、loads互轉(zhuǎn)。這篇文章主要介紹了python中的json、字典dict,需要的朋友可以參考下
    2018-06-06
  • 用Python下載一個(gè)網(wǎng)頁(yè)保存為本地的HTML文件實(shí)例

    用Python下載一個(gè)網(wǎng)頁(yè)保存為本地的HTML文件實(shí)例

    今天小編就為大家分享一篇用Python下載一個(gè)網(wǎng)頁(yè)保存為本地的HTML文件實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • Python讀取Pickle文件信息并計(jì)算與當(dāng)前時(shí)間間隔的方法分析

    Python讀取Pickle文件信息并計(jì)算與當(dāng)前時(shí)間間隔的方法分析

    這篇文章主要介紹了Python讀取Pickle文件信息并計(jì)算與當(dāng)前時(shí)間間隔的方法,涉及Python基于pickle模塊操作文件屬性相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-01-01
  • Python Cookie 讀取和保存方法

    Python Cookie 讀取和保存方法

    今天小編就為大家分享一篇Python Cookie 讀取和保存方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • Python3實(shí)時(shí)操作處理日志文件的實(shí)現(xiàn)

    Python3實(shí)時(shí)操作處理日志文件的實(shí)現(xiàn)

    本文主要介紹了Python3實(shí)時(shí)操作處理日志文件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 用Python實(shí)現(xiàn)一個(gè)打字速度測(cè)試工具來(lái)測(cè)試你的手速

    用Python實(shí)現(xiàn)一個(gè)打字速度測(cè)試工具來(lái)測(cè)試你的手速

    有很多小伙伴們都苦惱自己手速不夠,今天特地整理了這篇文章,教你用Python實(shí)現(xiàn)一個(gè)打字測(cè)試工具來(lái)測(cè)試你的打字速度,文中有非常詳細(xì)的代碼示例,對(duì)想練手速的小伙伴們很有用哦,需要的朋友可以參考下
    2021-05-05

最新評(píng)論