2010-03-25 16 views
8

Python是否有一個所有字符串池,並且它們是(字符串)單例嗎?在Python中彙集字符串

a = str(num) 
b = str(num) 

更精確的,在下面的代碼的一個或兩個字符串是在存儲器中創建?

+4

僅供參考,字符串不能是單身。單例是一個只能有一個實例的類,並且該實例必須是全局可訪問的。可以(希望)有'str'類的許多實例;因此它不是一個單身人士。 – zneak 2010-03-25 21:36:30

+10

你正在尋找的概念是字符串實習:http://en.wikipedia.org/wiki/String_interning – 2010-03-25 21:39:17

+0

@zneak謝謝你的評論。我的意思是像價值單身(池或字符串實習是正確的詞 - http://en.wikipedia.org/wiki/String_interning)。 – 2010-03-25 21:44:06

回答

16

字符串是Python中不變的,所以實現可以決定是否實習生(這是經常與C#相關的術語,這意味着某些字符串存儲在一個池中)或不是。

在您的示例中,您正在動態創建字符串。 CPython確實並不總是查看池以檢測字符串是否已經存在 - 這也沒有意義,因爲您首先必須保留內存才能創建字符串,然後將其與池內容進行比較(效率低下對於長字符串)。

但長度爲1的字符串,CPython的不看入池(參見 「stringobject.c」):使用不斷字符串時

a = str(num) 
b = str(num) 
print a is b # <-- this will print False in most cases (but try str(1) is str(1)) 

但是:

static PyStringObject *characters[UCHAR_MAX + 1]; 

... 

PyObject * 
PyString_FromStringAndSize(const char *str, Py_ssize_t size) 
{ 

... 

    if (size == 1 && str != NULL && 
    (op = characters[*str & UCHAR_MAX]) != NULL) 
    { 
     #ifdef COUNT_ALLOCS 
      one_strings++; 
     #endif 

     Py_INCREF(op); 
     return (PyObject *)op; 
    } 

... 

所以直接在您的代碼中,CPython使用相同的字符串實例:

a = "text" 
b = "text" 
print a is b # <-- this will print True 
+0

@Andidog:如果CPython沒有查看池以檢查字符串是否已經存在,那麼爲什麼在num等於5時print a是b打印true? – Brian 2010-03-25 21:57:17

+0

@布萊恩:對不起,這有點不準確。編輯我的答案以解釋CPython實現的方式。 – AndiDog 2010-03-25 22:09:16

+3

很好的答案。我要添加的唯一細節是注意Python沒有'intern()' – keturn 2010-03-25 22:15:50

1

字符串通常不是實習的。在你的例子中,將創建兩個字符串(0和9之間的值除外)。爲了驗證這一點,我們可以使用is操作者看到,如果兩個字符串相同的對象:

>>> str(1056) is str(1056) 
False 
+1

什麼樣: 在[1]:X = STR(5) 在[2]:Y = STR(5) 在[3]:ID(x)的 缺貨[3]:3077925280L In [4]:id(y) Out [4]:3077925280L ? – gruszczy 2010-03-25 21:38:04

+0

gruszczy:這是一個很好的問題。這是一個特殊情況,只適用於數字0到9。但總的來說,這個陳述是不正確的。我澄清了我的答案。 – 2010-03-25 21:50:32

+0

0到9是特定編譯器的特定情況(儘管承認它是大多數人使用的編譯器)。其他編譯器可以選擇不同數量的預定義字符串。 – Brian 2010-03-25 21:58:39

5

一般情況下,字符串不是用Python拘留,但他們有時似乎是:

>>> str(5) is str(5) 
True 
>>> str(50) is str(50) 
False 

這不是在Python,其中常見的對象可能的方式來優化罕見異常的人都沒有:

>>> int(5+0) is int(5+0) 
True 
>>> int(50+0) is int(50+0) 
True 
>>> int(500+0) is int(500+0) 
False 

請記住,所有這些細節在Python的實現和甚至是相同實現的版本之間都會有所不同。