歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Python的pyc文件與code對象詳解

發(fā)布時間:2017-08-10 15:48  回復(fù):0  查看:2781   最后回復(fù):2017-08-10 15:48  
本文和大家分享的主要是python 中的pyc 文件與 code 對象相關(guān)內(nèi)容,一起來看看吧,希望對大家 學(xué)習(xí)python有所幫助。
  python 對源程序編譯結(jié)果是生成一個  .pyc  文件. python 對  .py  文件的編譯結(jié)果是字節(jié)碼為了能復(fù)用而不需要重新編譯才有了寫成  .pyc  文件對于解釋器來說  PyCodeObject  對象才是真正編譯結(jié)果, pyc 文件只是這個對象在硬盤上的表現(xiàn)形式 .
   PyCodeObject
  [code.h] 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 */
   int co_firstlineno;   /* first source line number */
  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) */
   void *co_extra;
  } PyCodeObject;
  編譯器在對源代碼進(jìn)行編譯的時候每一個  Code Block  會創(chuàng)建一個  PyCodeObject  對象與這個代碼段相對應(yīng)代碼段的范圍可大可小 可以是整個 py 文件 可以是 class,  可以是函數(shù) .
Python的pyc文件與code對象詳解
   訪問PyCodeObject對象
  在python 有與 c 一級的對 PyCodeObject 簡單包裝 , code 對象 可以訪問到 PyCodeObject 的各個域 .
  >>> source = open('db.py').read()>>> co = compile(source, 'db.py', 'exec')>>> type(co)
  < class ' code'>>>> co.co_names
  ('pymysql', 'config', 'threading', 'RLock', 'Lock', 'create_table_template', 'ob
  ject', 'Model', 'str', 'm')
   寫入文件 PyMarshal_WriteObjectToFile
  向pyc 文件寫入數(shù)據(jù)主要是這幾個 有刪減 :
  [ marshal.c]
  typedef struct {
  FILE *fp;
  int depth;
  PyObject *str;
  char *ptr;
  char *end;
  char *buf;
  _Py_hashtable_t *hashtable;
  int version;
  } WFILE;
  #define w_byte( c, p) do {                               \
  if (( p)->ptr != ( p)->end || w_reserve(( p), 1))  \
  *( p)->ptr++ = ( c);                          \
  } while( 0)
  static void w_flush( WFILE *p)
  {
  assert( p->fp != NULL);
  fwrite( p->buf, 1, p->ptr - p->buf, p->fp);
  p->ptr = p->buf;
  }
  這是文件寫入定義的基本結(jié)構(gòu), fp 指向最后要寫入的文件 w_byte(c, p)  則是一個簡單的封裝以字節(jié)為單位的復(fù)制到 p->ptr 先行區(qū)中 w_flush(WFILE *p)  則是將緩沖區(qū)  p->buf  寫到文件中.p->ptr 也就是準(zhǔn)備寫到文件中的增量部分 .
   static void w_long(long x, WFILE *p)
  {
  w_byte(( char)( x      & 0xff), p);
  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( const  char *s, Py_ssize_t n, WFILE *p)
  {
  Py_ssize_t m;
   if (!n || p->ptr == NULL)
   return;
  m = p->end - p->ptr;
   if (p->fp != NULL) {
   if (n <= m) {
  memcpy(p->ptr, s, n);
  p->ptr += n;
  }
   else {
  w_flush(p);
  fwrite(s, 1, n, p->fp);
  }
  }
   else {
   if (n <= m || w_reserve(p, n - m)) {
  memcpy(p->ptr, s, n);
  p->ptr += n;
  }
  }
  }
  如在調(diào)用  PyMarshal_WriteLongToFile  會調(diào)用  w_long ,  數(shù)據(jù)將會一個字節(jié)字節(jié)的寫入到文件中 而調(diào)用 PyMarshal_WriteObjectToFile  也會調(diào)用  w_object ,  這個函數(shù)比較長 , 就不列出來了 .
  為了區(qū)分寫入的類型在寫入文件前會做一個動作 , 就是先將待寫入的對象類型寫進(jìn)去 :
  [ marshal.c]
  #define TYPE_NULL               '0'
  #define TYPE_NONE               'N'
  #define TYPE_FALSE              'F'
  #define TYPE_TRUE               'T'
  #define TYPE_STOPITER           'S'
  #define W_TYPE( t, p) do { \
  w_byte(( t) | flag, ( p)); \
  } while( 0)
  這個對象類型的標(biāo)識對讀取pyc 文件至關(guān)重要 因為對象寫入 pyc 文件后 所有數(shù)據(jù)都變成字節(jié)流 類型信息丟失 有了這個標(biāo)識 當(dāng)讀取這樣的標(biāo)識時 則預(yù)示著上一個對象結(jié)束 新的對象開始 也能知道新對象是什么類型的 .
  內(nèi)部也有機(jī)制處理共享對象減少字節(jié)碼中冗余信息 共享類型的屬于  TYPE_INTERNED .
   加載pyc文件 PyMarshal_ReadObjectFromFile
  看一下加載pyc 文件的過程 pyc 文件理解更加深刻 :
  PyObject * PyMarshal_ReadObjectFromFile( FILE *fp)
  {
  RFILE rf;
  PyObject *result;
  rf.fp = fp;
  rf.readable = NULL;
  rf.current_filename = NULL;
  rf.depth = 0;
  rf.ptr = rf.end = NULL;
  rf.buf = NULL;
  rf.refs = PyList_New(0);
  if ( rf.refs == NULL)
  return NULL;
  result = r_object( &rf);
  Py_DECREF( rf.refs);
  if ( rf.buf != NULL)
  PyMem_FREE( rf.buf);
  return result;
  }
  從  r_object  開始就開始從pyc 文件中讀入數(shù)據(jù) 并創(chuàng)建 PyCodeObject 對象 這個  r_object  是對  w_object  的逆運算當(dāng)讀到  TYPE_INTERNED  會將其后面的字符串讀入 將這個字符串進(jìn)行 intern 操作 .
來源: 棲遲於一丘
您還未登錄,請先登錄

熱門帖子

最新帖子

?