>>importsys>>>sys.getsizeof(1000)28>>>sys.getsizeof(2000)28>>>sys.getsizeof("python")55>>>sys.getsizeof("java")53如上,整數對象所占用的內存都是" />

欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python字符串對象實現原理詳解

系統 1636 0

在Python世界中將對象分為兩種:一種是定長對象,比如整數,整數對象定義的時候就能確定它所占用的內存空間大小,另一種是變長對象,在對象定義時并不知道是多少,比如:str,list, set, dict等。

            
>>> import sys
>>> sys.getsizeof(1000)
28
>>> sys.getsizeof(2000)
28
>>> sys.getsizeof("python")
55
>>> sys.getsizeof("java")
53
          

如上,整數對象所占用的內存都是28字節,和具體的值沒關系,而同樣都是字符串對象,不同字符串對象所占用的內存是不一樣的,這就是變長對象,對于變長對象,在對象定義時是不知道對象所占用的內存空間是多少的。

字符串對象在Python內部用PyStringObject表示,PyStringObject和PyIntObject一樣都屬于不可變對象,對象一旦創建就不能改變其值。(注意:變長對象和不可變對象是兩個不同的概念)。PythonStringObject的定義:

            
[stringobject.h]
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
} PyStringObject;
          

不難看出Python的字符串對象內部就是由一個字符數組維護的,在整數的實現原理一文中提到PyObject_HEAD,對于PyObject_VAR_HEAD就是在PyObject_HEAD基礎上多出一個ob_size屬性:

            
[object.h]
#define PyObject_VAR_HEAD  
 PyObject_HEAD   
 int ob_size; /* Number of items in variable part */
typedef struct {
 PyObject_VAR_HEAD
} PyVarObject;
          
  • ob_size保存了變長對象中元素的長度,比如PyStringObject對象"Python"的ob_size為6。
  • ob_sval是一個初始大小為1的字符數組,且ob_sval[0] = '\0',但實際上創建一個PyStringObject時ob_sval指向的是一段長為ob_size+1個字節的內存。
  • ob_shash是字符串對象的哈希值,初始值為-1,在第一次計算出字符串的哈希值后,會把該值緩存下來,賦值給ob_shash。
  • ob_sstate用于標記該字符串對象是否進過intern機制處理(后文會介紹)。

PYSTRINGOBJECT對象創建過程

            
[stringobject.c]
PyObject * PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;
assert(str != NULL);
size = strlen(str);
// [1]
if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {
PyErr_SetString(PyExc_OverflowError,
"string is too long for a Python string");
return NULL;
}
// [2]
if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
null_strings++;
#endif
Py_INCREF(op);
return (PyObject *)op;
}
// [3]
if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
#ifdef COUNT_ALLOCS
one_strings++;
#endif
Py_INCREF(op);
return (PyObject *)op;
}
// [4]
/* Inline PyObject_NewVar */
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
if (op == NULL)
return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyString_Type, size);
op->ob_shash = -1;
op->ob_sstate = SSTATE_NOT_INTERNED;
Py_MEMCPY(op->ob_sval, str, size+1);
/* share short strings */
if (size == 0) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
nullstring = op;
Py_INCREF(op);
} else if (size == 1) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
}
return (PyObject *) op;
}
          
  • 如果字符串的長度超出了Python所能接受的最大長度(32位平臺是2G),則返回Null。
  • 如果是空字符串,那么返回特殊的PyStringObject,即nullstring。
  • 如果字符串的長度為1,那么返回特殊PyStringObject,即onestring。
  • 其他情況下就是分配內存,初始化PyStringObject,把參數str的字符數組拷貝到PyStringObject中的ob_sval指向的內存空間。

字符串的INTERN機制

PyStringObject的ob_sstate屬性用于標記字符串對象是否經過intern機制處理,intern處理后的字符串,比如"Python",在解釋器運行過程中始終只有唯一的一個字符串"Python"對應的PyStringObject對象。

            
>>> a = "python"
>>> b = "python"
>>> a is b
True
          

如上所示,創建a時,系統首先會創建一個新的PyStringObject對象出來,然后經過intern機制處理(PyString_InternInPlace),接著查找經過intern機制處理的PyStringObject對象,如果發現有該字符串對應的PyStringObject存在,則直接返回該對象,否則把剛剛創建的PyStringObject加入到intern機制中。由于a和b字符串字面值是一樣的,因此a和b都指向同一個PyStringObject("python")對象。那么intern內部又是一個什么樣的機制呢?

            
[stringobject.c]
static PyObject *interned;
void PyString_InternInPlace(PyObject **p)
{
register PyStringObject *s = (PyStringObject *)(*p);
PyObject *t;
if (s == NULL || !PyString_Check(s))
Py_FatalError("PyString_InternInPlace: strings only please!");
/* If it's a string subclass, we don't really know what putting
it in the interned dict might do. */
// [1]
if (!PyString_CheckExact(s))
return;
// [2]
if (PyString_CHECK_INTERNED(s))
return;
// [3]
if (interned == NULL) {
interned = PyDict_New();
if (interned == NULL) {
PyErr_Clear(); /* Don't leave an exception */
return;
}
}
t = PyDict_GetItem(interned, (PyObject *)s);
if (t) {
Py_INCREF(t);
Py_DECREF(*p);
*p = t;
return;
}
if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) {
PyErr_Clear();
return;
}
/* The two references in interned are not counted by refcnt.
The string deallocator will take care of this */
Py_REFCNT(s) -= 2;
PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL;
}
          

1.先類型檢查,intern機制只處理字符串

2.如果該PyStringObject對象已經進行過intern機制處理,則直接返回

3.interned其實一個字典對象,當它為null時,初始化一個字典對象,否則,看該字典中是否存在一個key為(PyObject *)s的value,如果存在,那么就把該對象的引用計數加1,臨時創建的那個對象的引用計數減1。否則,把(PyObject *)s同時作為key和value添加到interned字典中,與此同時它的引用計數減2,這兩個引用計數減2是因為被interned字典所引用,但這兩個引用不作為垃圾回收的判斷依據,否則,字符串對象永遠都不會被垃圾回收器收集了。

Python字符串對象實現原理詳解_第1張圖片

上述代碼中,給b賦值為"python"后,系統中創建了幾個PyStringObject對象呢?答案是:2,在創建b的時候,一定會有一個臨時的PyStringObject作為字典的key在interned中查找是否存在一個PyStringObject對象的值為"python"。

字符串的緩沖池

字符串除了有intern機制緩存字符串之外,字符串還有一種專門的短字符串緩沖池characters。用于緩存字符串長度為1的PyStringObject對象。

            
static PyStringObject *characters[UCHAR_MAX + 1]; //UCHAR_MAX = 255
          

創建長度為1的字符串時流程:

            
...
else if (size == 1) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
          
  • 首先創建一個PyStringObject對象。
  • 進行intern操作
  • 將PyStringObject緩存到characters中
  • 引用計數增1

Python字符串對象實現原理詳解_第2張圖片

總結:

1. 字符串用PyStringObject表示

2. 字符串屬于變長對象

3. 字符串屬于不可變對象

4. 字符串用intern機制提高python的效率

5. 字符串有專門的緩沖池存儲長度為1的字符串對象

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 免费在线黄色片 | 日本免费在线一区 | 黄色影片在线免费观看 | 成人亚洲一区二区色情无码潘金莲 | 国产精品九九九久久九九 | 久热这里只有精品视频6 | 亚洲在线影院 | 91aiai.com | 日本黄色片免费看 | 亚洲热久久| 免费观看一级毛片 | 国产亚洲欧美另类第一页 | xx520av| 97视频免费播放观看在线视频 | 综合精品| a级片在线免费播放 | 日本一区二区三区四区 | 青青久久| 日日干夜夜操 | 久久伦理中文字幕 | 天堂热 | 精品视频第一页 | 一级a级国产不卡毛片 | 男女免费爽爽爽在线视频 | 欧美经典成人在观看线视频 | 欧美激情欧美激情在线五月 | av在线播放国产 | 2021国产精品成人免费视频 | 91影片 | 日韩中文一区 | 日本大片在线观看免费视频 | 久久久99国产精品免费 | 久久久国产99久久国产一 | 91视频视频 | 国产精品嫩草影视在线观看 | 夜夜嘿视频免费看 | 日本高清在线中文字幕网 | 九九久久久 | 成人深夜视频在线观看 | 国产一区二区三区久久久久久久久 | 欧美一区二区三区爽大粗免费 |