Python內核源碼解析與C/CPP-API拓展編程(一)PyObject

下載Python源碼

我這裏使用Python3.5做爲學習的源碼python

目錄結構

|
--- Include: 包括Python提供的全部頭文件, 能夠用於c/c++擴展
--- Lib: Python的標準庫, 所有都是用python寫的
--- Modules: 包含了C語言編寫的模塊, 好比random, StringIO 等
--- Parser: 包含了python解釋器中的scanner和parser部分,也就是詞法分析和語法分析部分,一個相似yacc同樣根據規則自動生成
--- Objects: 包含全部Python的內置對象,整數, list, dict等.也包含了運行時python須要的全部內部使用的對象的實現
--- Python: 包含了python解釋器中Compiler和執行引擎部分,是python運行的核心所在
--- PCBuild:包含了vs工程文件

調試方法:

基於C++的調試對於已經到Python虛擬機中存儲起來的字節碼命令是沒法被觀察到的,咱們只能把它們解析成AST才能看懂字節碼在解釋器內存中的狀態,因此這裏咱們借用Python解釋器裏的C_API來輸出咱們的對象:c++

PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);

# eg:
PyObject_Print(v, stdout, 0);

Python架構

Python的總體架構可分爲3個模塊架構

  1. 內建模塊 Python提供的大量的模塊、庫以及用戶自定義的模塊,好比import math,math就是python的內建模塊。
  2. Python的運行時環境,包括對象/類型系統(Object/Type structures)、內存分配器(Memory Allocator)和運行時狀態信息(Current State of Python)。 對象/類型系統:包含Python中存在的各類內建對象,int、list、dict等,以及用戶自定義的各類類型和對象。
  • 內存分配器:負責Python中建立對象時,對內存的申請工做,其實是Python運行時與C中malloc的一層接口。
  • 運行時狀態:維護瞭解釋器在執行字節碼時不一樣的狀態(正常狀態和異常狀態)之間的切換,有窮狀態機。
  1. Python解釋器或稱爲虛擬機,包括Scanner詞法分析器,Parser語法分析器 ,Compiler編譯器,Code Evaluator虛擬機。
  • Scanner:將輸入的Python源代碼或從命令輸入的Python代碼分割成一個個的token。
  • Parser:在Scanner的分析結果上進行語法分析,創建抽象語法樹(AST)。
  • Compiler:根據創建的AST生成指令集合—-Python字節碼(byte code)
  • Code Evaluator:執行字節碼。

PyObject

python玩家都知道,在python中,萬物皆對象,python的源碼中是經過下面的代碼去定義每個對象的。
object.hdom

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

結構體中包含了Py_ssize_t、_typeobject兩個成員,下面一個個來看它的成員的定義和意義。學習

_PyObject_HEAD_EXTRA

object.hui

#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif

Py_ssize_t

往下檢索能夠看到定義
pyport.hlua

typedef Py_intptr_t     Py_ssize_t;

pyport.h操作系統

typedef intptr_t        Py_intptr_t;

vcstdint.h.net

//預編譯判斷操做系統類型
#ifdef _WIN64 // [若是是64位操做系統
   typedef __int64           intptr_t;
   typedef unsigned __int64  uintptr_t;
#else // _WIN64 ][32位操做系統
   typedef _W64 int               intptr_t;
   typedef _W64 unsigned int      uintptr_t;
#endif // _WIN64 ]

__w64是一個編譯器相關的關鍵字, 意思是說這個類型使用64位兼容方式編譯, 在編譯64位程序時指針就被視爲64位寬, 而不是32位. int也有可能會被視爲64位. __int64 原形爲指針

typedef int __w64 __int64

換句話說在64位系統中, 它是64位int整型, 32位系統就是int. _W64 是爲了兼容64位系統存在的. 因此 Py_ssize_t 的本質就是 int類型的變量。 將上面的定義所有迴帶化簡之後,代碼變成

typedef struct _object {
    __int64 ob_refcnt;//int ob_refcnt
    struct _typeobject *ob_type;
} PyObject;
做用

表示變量引用次數, python的垃圾回收機制基於引用計數, 在python運行的過程當中當某個對象引用計數減小到0時, 就能夠將該變量從堆上刪除,釋放內存。咱們能夠檢索到引用計數的處理定義。

#define Py_INCREF(op)   ((op)->ob_refcnt++)          //增長計數
#define Py_DECREF(op)      \                         //減小計數        
     if (--(op)->ob_refcnt != 0)    \
         ;        \
     else         \
         __Py_Dealloc((PyObject *)(op))

引用計數爲0時,該對象生命週期結束,python釋放內存。

  • 引用計數機制的優勢:
  1. 簡單
  2. 實時性:一旦沒有引用,內存就直接釋放了。不用像其餘機制等到特定時機。實時性還帶來一個好處:處理回收內存的時間分攤到了運行時。
  • 引用計數機制的缺點:
  1. 維護引用計數消耗資源
  2. 循環引用

好了到此爲止,涉及python的垃圾回收(GC)後面專門會分一篇文章來說解

_typeobject

表示了對象的類型信息, 諸如int, string, function,class等,這裏作一個簡述,具體細節留到下一篇python類型對象去寫。

相關文章
相關標籤/搜索