SlideShare una empresa de Scribd logo
1 de 48
Descargar para leer sin conexión
CPython 原始碼解析
果凍
http://goo.gl/3mq3Y
簡介
● 中興大學資工系
● 任職於曼克斯
● 接觸 python 時間有七年
● 喜歡學習新的程式語言
● C、C++、java、golang。
● About me: http://about.
me/ya790206
大綱
1. 介紹 C 語言如何模擬繼承
2. 介紹 python 的根本物件 PyObject
3. 介紹 PyType
4. 介紹 PyIntObject
5. 介紹 PyStringObject
6. 介紹 PyList
https://github.com/ya790206/CPython
ptr->data
物件起始位址 data屬性
離物件起
始位址置
的差
data屬性所在位址
#include <stdio.h>
#include <stdint.h>
struct classA{
int32_t data;
};
struct classB{
int8_t data[4];
};
struct classC{
int32_t data;
int32_t data1;
};
int main(){
struct classA obj;
struct classA *pa = &obj;
struct classB *pb = (struct classB*)&obj;
struct classC *pc = (struct classC*)&obj;
obj.data = 0;
printf("%d, %d, %d, %d, %d, %dn", pa->data, pb->data[0], pb->data[1], pb-
>data[2], pb->data[3], pc->data);
obj.data = 1;
printf("%d, %d, %d, %d, %d, %dn", pa->data, pb->data[0], pb->data[1], pb-
>data[2], pb->data[3], pc->data);
obj.data = 1 << 8;
printf("%d, %d, %d, %d, %d, %dn", pa->data, pb->data[0], pb->data[1], pb-
>data[2], pb->data[3], pc->data);
printf("%p %pn",&(pb->data[1]) - &(((struct classB*)0)->data[1]), pb);
return 0;
}
0, 0, 0, 0, 0, 0
1, 1, 0, 0, 0, 1
256, 0, 1, 0, 0, 256
0x7fff613428a0 0x7fff613428a0
Little-Endian
classA
classB
classC
data
data
data
[0]
data
[1]
data
[2]
data
[3]
data data1
obj
32
#include <stdio.h>
typedef void (*myfunc)();
#define Father_HEADER 
myfunc init;
struct father{
Father_HEADER
};
struct child1{
Father_HEADER
myfunc custom1;
};
struct child2{
Father_HEADER
myfunc custom2;
};
C 語言模仿繼承方法
void father_init(){
printf("call father initn");
}
void child1_init(){
printf("call child1 initn");
}
void child2_init(){
printf("call child2 initn");
}
void call_init(struct father *obj){
obj->init();
}
int main(){
struct father f_obj = {father_init};
struct child1 c1_obj = {child1_init, 0};
struct child2 c2_obj = {child2_init, 0};
call_init(&f_obj);
call_init((struct father*) &c1_obj);
call_init((struct father*) &c2_obj);
return 0;
}
結果
call father init
call child1 init
call child2 init
object.h
Python 物件根本:
1. PyObject
a. 如 int
b. PyObject_HEAD
2. PyVarObject
a. 多了 ob_size 欄位
b. 如 string, list
c. PyObject_VAR_HEAD
ref: http://docs.python.org/2/c-api/structures.html
#define PyObject_HEAD 
_PyObject_HEAD_EXTRA 
Py_ssize_t ob_refcnt; 
struct _typeobject *ob_type;
#define PyObject_VAR_HEAD 
PyObject_HEAD 
Py_ssize_t ob_size; /* Number of items in variable part */
typedef struct _object {
PyObject_HEAD
} PyObject;
typedef struct {
PyObject_VAR_HEAD
} PyVarObject;
ob_refcnt:
1. Reference Counting
#define Py_INCREF(op) ( 
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA

((PyObject*)(op))->ob_refcnt++)
ob_type:
a. 該物件的 type,該物件能作的動作
b. PyType_Type 物件的此欄位指向自己
c. 其他屬於 PyTypeObject 的物件此欄位指向
PyType_Type 物件
d. 其他物件則指向他所屬的 PyTypeObject 物件
PyIntObject
ob_type
PyType_Type
ob_type
PyInt_Type
ob_type
ob_type
PyObject
1. PyClassObject
2. PyInstanceObject
3. PyMethodObject
4. PyCodeObject
5. Py_complex
6. PyDictObject
7. PyFileObject
8. PyFunctionObject
9. PyIntObject
10. PySetObject
等等
PyVarObject
1. PyByteArrayObject
2. PyFrameObject
3. PyListObject
4. PyStringObject
5. PyTupleObject
PyTypeObject
1. 存放該物件可以被執行的方法
2. 如 PyInt_Type 存放 Int 型別所支援的方法,他
支援 tp_str,所以我們可以使用 str(5)。當我們
呼叫 str(5),他會呼叫相對應的 c function,
int_to_decimal_string。
3. 因為 tp_call 的值是 0,因此 int 型別不能被呼
叫。tp_call 對應到 python 的 __call__ 方法。
PyTypeObject
#define Py_TYPE(ob) (((PyObject*)
(ob))->ob_type)
PyObject *v;
Py_TYPE(v)->tp_free((PyObject *)v);
PyIntObject
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
PyIntObject
1. PyInt_FromLong(long ival) 建立整數的函數
2. 預設 CPython 實作,-5 ~ 256 的整數物件都
是 singletons。
3. 使用 free_list 來減少沒必的 memory
allocate/deallocate。
4. 每次向python memory system系統要求可容
納 N_INTOBJECTS 個整數的空間。
5. 做連續 n 次加法時,會產生 n - 1 個暫時物
件。因 int_add 的回傳值是 PyObject。
ob_refcnt ob_type
ob_refcnt ob_type
ob_refcnt ob_type
ob_refcnt ob_type
_intblock *next
PyIntObject
objects
[N_INTOBJECTS];
PyIntBlock
fill_free_list 的原理
free_list
1 2 3 4 5 6 7 8
free list: 6 -> 7 -> 8
如果在第三個位置的物件被刪除後
1 2 3 4 5 6 7 8
free list: 3 -> 6 -> 7 -> 8
PyString
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
} PyStringObject;
HEA
DE
R
ob_
sha
sh
ob_
ssta
te
ob_sv
al[1]
空
字
串
0
abc a b c 0
1. PyStringObject_SIZE + size
2. ob_sval[1], ob_sval[2], ob_sval[3],反正 C不會檢
查索引有沒有超過陣列大小
PyString
1. 對於特定字串,使用 intern 機制,增加物件重
複使用率。但是並無增加太多效率。
2. 在CPython中,一個 byte的字串和空字串是
singletons 物件。
PyObject *
PyString_InternFromString(const char *cp)
{
PyObject *s = PyString_FromString(cp);
if (s == NULL)
return NULL;
PyString_InternInPlace(&s);
return s;
}
PyString_InternInPlace(PyObject **p)
1. 檢查是否是字串,(不是字串)或(是NULL),則
離開。
2. 如果是字串子類別,則離開。
3. 如果已經是 intern 字串,則離開
4. 如果 intern dict 中有相同字串,則將原本的字
串參考計數減1,傳回 intern 字串(傳位址)
5. 如果字串不在 intern dict 裡,則把自己插入到
intern dict 裡。
6. 把自己的參考計數減2
7. 把字串狀態設定成
SSTATE_INTERNED_MORTAL
why Py_REFCNT(s) -= 2?
1. 因為當 intern dict 的 key ,被加一
2. 又當 intern dict 的 value ,再被加一
3. 這兩個參考計數只被 intern dict使用,如果不
減2,則永遠不會被消滅。(至少有 intern dict
的 key/value 指向他)
哪些會呼叫PyString_InternInPlace
1. 字串長度小於等於1
2. 呼叫 PyString_InternFromString
3. 使用者呼叫 intern(對應 C 的 builtin_intern)
string_concat
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
Py_MEMCPY(op->ob_sval, a->ob_sval, Py_SIZE(a));
Py_MEMCPY(op->ob_sval + Py_SIZE(a), b->ob_sval, Py_SIZE(b));
op->ob_sval[size] = '0';
return (PyObject *) op;
1. 每次完成字串加法的動作後,傳回新的物件
2. 每次取得記憶體空間,是使用
PyObject_MALLOC
Python memory management
PyIntBlock
PyIntObject PyString
string_join
/* Allocate result space. */
res = PyString_FromStringAndSize((char*)
NULL, sz);
if (res == NULL) {
Py_DECREF(seq);
return NULL;
}
1. 只分配一次記憶體
/* Catenate everything. */
p = PyString_AS_STRING(res);
for (i = 0; i < seqlen; ++i) {
size_t n;
item = PySequence_Fast_GET_ITEM(seq, i);
n = PyString_GET_SIZE(item);
Py_MEMCPY(p, PyString_AS_STRING(item), n);
p += n;
if (i < seqlen - 1) {
Py_MEMCPY(p, sep, seplen);
p += seplen;
}
}
Py_DECREF(seq);
return res;
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
PyListObject
why ob_item 是二維指標?
PyOb
ject *
PyOb
ject *
PyOb
ject *
PyOb
ject *
PyOb
ject *
PyObj
ect
PyObj
ect
PyObj
ect
PyList_New
1. static PyListObject *free_list[PyList_MAXFREELIST];
2. nbytes = size * sizeof(PyObject *);
3. op = PyObject_GC_New(PyListObject, &PyList_Type);
4. op->ob_item = (PyObject **) PyMem_MALLOC(nbytes);
1. op 用來維護 list 的相關資訊,如 ob_size, ob_refcnt
2. op->ob_item 存放 list 裡元素所在位址。
list_dealloc
1. Py_XDECREF(op->ob_item[i]);
2. PyMem_FREE(op->ob_item);
3. 二選一
a. free_list[numfree++] = op;
b. Py_TYPE(op)->tp_free((PyObject *)op);
app1(Append)
1. list_resize(self, n+1)
2. Py_INCREF(v);
3. PyList_SET_ITEM(self, n, v);
list_resize
1. new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
2. new_allocated += newsize;
3. PyMem_RESIZE(items, PyObject *, new_allocated);
4. self->ob_item = items;
5. Py_SIZE(self) = newsize;
6. self->allocated = new_allocated;
實際上,PyMem_RESIZE 最後呼叫 realloc。
Python 的 list行為與 C++ 的 vector 相似
#define PyList_GET_ITEM(op, i)
(((PyListObject *)(op))->ob_item[i])
#define PyList_SET_ITEM(op, i, v)
(((PyListObject *)(op))->ob_item[i] = (v))
#define PyList_GET_SIZE(op) Py_SIZE(op)
ins1
if (where > n)
where = n;
items = self->ob_item;
for (i = n; --i >= where; )
items[i+1] = items[i];
Py_INCREF(v);
items[where] = v;
return 0;
參考資料
1. python c api
2. Extending and Embedding the
Python Interpreter
3. Python源码剖析
4. python source code
Q & A
謝謝大家
The manx:
http://www.themanxgroup.tw/
The manx production:
http://lucky-lane.com/
C python 原始碼解析 投影片

Más contenido relacionado

La actualidad más candente

数据结构回顾
数据结构回顾数据结构回顾
数据结构回顾Zehua HONG
 
Introduction to Basic Haskell Components (In Chinese)
Introduction to Basic Haskell Components (In Chinese)Introduction to Basic Haskell Components (In Chinese)
Introduction to Basic Haskell Components (In Chinese)ChengHui Weng
 
Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿jiannrong
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7Justin Lin
 
Golangintro
GolangintroGolangintro
Golangintro理 傅
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Androidkoji lin
 
OOP in C - Virtual Function (Chinese Version)
OOP in C - Virtual Function (Chinese Version)OOP in C - Virtual Function (Chinese Version)
OOP in C - Virtual Function (Chinese Version)Kai-Feng Chou
 
Java 開發者的函數式程式設計
Java 開發者的函數式程式設計Java 開發者的函數式程式設計
Java 開發者的函數式程式設計Justin Lin
 
竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗乐群 陈
 
Python speed up with numba
Python speed up with numbaPython speed up with numba
Python speed up with numbaJiang Wu
 
Python 入门
Python 入门Python 入门
Python 入门kuco945
 
Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍dennis zhuang
 
Intro to C++ Basic
Intro to C++ BasicIntro to C++ Basic
Intro to C++ BasicShih Chi Lin
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambdakoji lin
 

La actualidad más candente (19)

数据结构回顾
数据结构回顾数据结构回顾
数据结构回顾
 
Introduction to Basic Haskell Components (In Chinese)
Introduction to Basic Haskell Components (In Chinese)Introduction to Basic Haskell Components (In Chinese)
Introduction to Basic Haskell Components (In Chinese)
 
Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
 
Golangintro
GolangintroGolangintro
Golangintro
 
Ch6 函式
Ch6 函式Ch6 函式
Ch6 函式
 
Use Lambdas in Android
Use Lambdas in AndroidUse Lambdas in Android
Use Lambdas in Android
 
OOP in C - Virtual Function (Chinese Version)
OOP in C - Virtual Function (Chinese Version)OOP in C - Virtual Function (Chinese Version)
OOP in C - Virtual Function (Chinese Version)
 
Java 開發者的函數式程式設計
Java 開發者的函數式程式設計Java 開發者的函數式程式設計
Java 開發者的函數式程式設計
 
竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗
 
Ppt 120-126
Ppt 120-126Ppt 120-126
Ppt 120-126
 
Python程式設計 - 串列資料應用
Python程式設計 - 串列資料應用 Python程式設計 - 串列資料應用
Python程式設計 - 串列資料應用
 
Python speed up with numba
Python speed up with numbaPython speed up with numba
Python speed up with numba
 
Python 入门
Python 入门Python 入门
Python 入门
 
Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍
 
Python 迴圈作業
Python 迴圈作業Python 迴圈作業
Python 迴圈作業
 
Intro to C++ Basic
Intro to C++ BasicIntro to C++ Basic
Intro to C++ Basic
 
Python程式設計 - 迴圈作業
Python程式設計 - 迴圈作業Python程式設計 - 迴圈作業
Python程式設計 - 迴圈作業
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambda
 

Destacado

Blender+Python script模擬電影裡的GUI介面動畫
Blender+Python script模擬電影裡的GUI介面動畫Blender+Python script模擬電影裡的GUI介面動畫
Blender+Python script模擬電影裡的GUI介面動畫David Chen
 
recover_pdb 原理與介紹
recover_pdb 原理與介紹recover_pdb 原理與介紹
recover_pdb 原理與介紹kao kuo-tung
 
鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論
鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論
鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論David Chen
 
關於我和我的2015作品們
關於我和我的2015作品們關於我和我的2015作品們
關於我和我的2015作品們David Chen
 
再生接收機工作坊 - Regenerative Radio Workshop
再生接收機工作坊 - Regenerative Radio Workshop再生接收機工作坊 - Regenerative Radio Workshop
再生接收機工作坊 - Regenerative Radio WorkshopDavid Chen
 
Git 實務圖解
Git 實務圖解Git 實務圖解
Git 實務圖解Pokai Chang
 

Destacado (7)

Blender+Python script模擬電影裡的GUI介面動畫
Blender+Python script模擬電影裡的GUI介面動畫Blender+Python script模擬電影裡的GUI介面動畫
Blender+Python script模擬電影裡的GUI介面動畫
 
recover_pdb 原理與介紹
recover_pdb 原理與介紹recover_pdb 原理與介紹
recover_pdb 原理與介紹
 
555
555555
555
 
鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論
鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論
鳳新高中電腦研究社(FHCRC)102級下學期社課 - 通訊網路概論
 
關於我和我的2015作品們
關於我和我的2015作品們關於我和我的2015作品們
關於我和我的2015作品們
 
再生接收機工作坊 - Regenerative Radio Workshop
再生接收機工作坊 - Regenerative Radio Workshop再生接收機工作坊 - Regenerative Radio Workshop
再生接收機工作坊 - Regenerative Radio Workshop
 
Git 實務圖解
Git 實務圖解Git 實務圖解
Git 實務圖解
 

Similar a C python 原始碼解析 投影片

Py ladies 0928
Py ladies 0928Py ladies 0928
Py ladies 0928Yen_CY
 
基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程zhangdaiping
 
A brief introduction to Python
A brief introduction to PythonA brief introduction to Python
A brief introduction to Pythonbugway
 
Py + gi 高效 c 庫整合方案
Py +  gi   高效 c 庫整合方案Py +  gi   高效 c 庫整合方案
Py + gi 高效 c 庫整合方案Leo Zhou
 
腾讯大讲堂05 面向对象应对之道
腾讯大讲堂05 面向对象应对之道腾讯大讲堂05 面向对象应对之道
腾讯大讲堂05 面向对象应对之道George Ang
 
iPhone,ios,Object-c基础入门
iPhone,ios,Object-c基础入门iPhone,ios,Object-c基础入门
iPhone,ios,Object-c基础入门Lucien Li
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门Lucien Li
 

Similar a C python 原始碼解析 投影片 (10)

Py ladies 0928
Py ladies 0928Py ladies 0928
Py ladies 0928
 
Py ladies 0928
Py ladies 0928Py ladies 0928
Py ladies 0928
 
基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程基于原型的JavaScript面向对象编程
基于原型的JavaScript面向对象编程
 
ios分享
ios分享ios分享
ios分享
 
C語言結構與串列
C語言結構與串列 C語言結構與串列
C語言結構與串列
 
A brief introduction to Python
A brief introduction to PythonA brief introduction to Python
A brief introduction to Python
 
Py + gi 高效 c 庫整合方案
Py +  gi   高效 c 庫整合方案Py +  gi   高效 c 庫整合方案
Py + gi 高效 c 庫整合方案
 
腾讯大讲堂05 面向对象应对之道
腾讯大讲堂05 面向对象应对之道腾讯大讲堂05 面向对象应对之道
腾讯大讲堂05 面向对象应对之道
 
iPhone,ios,Object-c基础入门
iPhone,ios,Object-c基础入门iPhone,ios,Object-c基础入门
iPhone,ios,Object-c基础入门
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门
 

Más de kao kuo-tung

用 Open source 改造鍵盤
用 Open source 改造鍵盤用 Open source 改造鍵盤
用 Open source 改造鍵盤kao kuo-tung
 
Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例kao kuo-tung
 
Openstack swift, how does it work?
Openstack swift, how does it work?Openstack swift, how does it work?
Openstack swift, how does it work?kao kuo-tung
 
Why is a[1] fast than a.get(1)
Why is a[1]  fast than a.get(1)Why is a[1]  fast than a.get(1)
Why is a[1] fast than a.get(1)kao kuo-tung
 
減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法kao kuo-tung
 
Openstack taskflow 簡介
Openstack taskflow 簡介Openstack taskflow 簡介
Openstack taskflow 簡介kao kuo-tung
 
Async: ways to store state
Async:  ways to store stateAsync:  ways to store state
Async: ways to store statekao kuo-tung
 
Docker 原理與實作
Docker 原理與實作Docker 原理與實作
Docker 原理與實作kao kuo-tung
 
那些年,我們一起看的例外
那些年,我們一起看的例外那些年,我們一起看的例外
那些年,我們一起看的例外kao kuo-tung
 
Python 中 += 與 join比較
Python 中 += 與 join比較Python 中 += 與 join比較
Python 中 += 與 join比較kao kuo-tung
 
Garbage collection 介紹
Garbage collection 介紹Garbage collection 介紹
Garbage collection 介紹kao kuo-tung
 
Python 如何執行
Python 如何執行Python 如何執行
Python 如何執行kao kuo-tung
 

Más de kao kuo-tung (15)

用 Open source 改造鍵盤
用 Open source 改造鍵盤用 Open source 改造鍵盤
用 Open source 改造鍵盤
 
Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例Immutable infrastructure 介紹與實做:以 kolla 為例
Immutable infrastructure 介紹與實做:以 kolla 為例
 
Python to scala
Python to scalaPython to scala
Python to scala
 
Intorduce to Ceph
Intorduce to CephIntorduce to Ceph
Intorduce to Ceph
 
Openstack swift, how does it work?
Openstack swift, how does it work?Openstack swift, how does it work?
Openstack swift, how does it work?
 
Why is a[1] fast than a.get(1)
Why is a[1]  fast than a.get(1)Why is a[1]  fast than a.get(1)
Why is a[1] fast than a.get(1)
 
減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法減少重複的測試程式碼的一些方法
減少重複的測試程式碼的一些方法
 
Openstack taskflow 簡介
Openstack taskflow 簡介Openstack taskflow 簡介
Openstack taskflow 簡介
 
Async: ways to store state
Async:  ways to store stateAsync:  ways to store state
Async: ways to store state
 
Openstack 簡介
Openstack 簡介Openstack 簡介
Openstack 簡介
 
Docker 原理與實作
Docker 原理與實作Docker 原理與實作
Docker 原理與實作
 
那些年,我們一起看的例外
那些年,我們一起看的例外那些年,我們一起看的例外
那些年,我們一起看的例外
 
Python 中 += 與 join比較
Python 中 += 與 join比較Python 中 += 與 join比較
Python 中 += 與 join比較
 
Garbage collection 介紹
Garbage collection 介紹Garbage collection 介紹
Garbage collection 介紹
 
Python 如何執行
Python 如何執行Python 如何執行
Python 如何執行
 

C python 原始碼解析 投影片