前置知識點
當我們創建一個對象時,我們要知道它內部干了些什么
- 1.創建了一個隨機id,開辟了一片內存地址
- 2.自動聲明了這個對象的類型type
- 3.給這個對象賦值value
小例子
a = 1
print(id(1))
print(id(a))
print(type(a))
結果
4470700832
4470700832
<class 'int'>
可以明顯看出數字1的內存地址跟對象a的內存地址是一樣的,a = 1
的原理是首先內存中有一個id=4470700832
,type=int
,value=1
的對象,然后創建a對象指向1,此時a的id、type、value跟1的一樣
is和==的區別
上面分析了創建對象的整個內存過程,那么接下來理解is和==的區別就好多了
- is:用於判斷兩個變量引用對象是否為同一個,既比較對象的地址。
- ==:用於判斷引用變量引用對象的值是否相等,默認調用對象的
__eq__()
方法。
>>> a = 257
>>> b = 257
>>> id(a)
140204598140720
>>> id(b)
140204598140400
>>> print(a is b)
False
>>> print(a == b)
True
根據我們上面講解的,a的地址和b的地址應該跟257的地址相同,但是現在顯然不同,這是為什么呢?下面會說明
整數緩存問題
Python 僅僅對比較小的整數對象進行緩存(范圍為[-5, 256])
緩存起來,而並非是所有整數對象。需要注意的是,這僅僅是在命令行中執行,而在Pycharm
或者保存為文件執行,結果是不一樣 的,這是因為解釋器做了一部分優化(范圍是[-5,任意正整數])。
總結
- is 比較兩個對象的 id 值是否相等,是否指向同一個內存地址
- == 比較的是兩個對象的內容是否相等,值是否相等
- 小整數對象[-5,256]在全局解釋器范圍內被放入緩存供重復使用
- is 運算符比 == 效率高,在變量和 None 進行比較時,應該使用 is。
字符串駐留機制
什么是字符串駐留?
字符串駐留是一種僅保存一份相同且不可變字符串的方法。
基本原理
系統維護interned
字典,記錄已被駐留的字符串對象。
當字符串對象a需要駐留時,先在interned
檢測是否存在,若存在則指向存在的字符串對象,a的引用計數減1;
若不存在,則記錄a到interned
中
為什么要字符串駐留?
- 顯而易見,節省大量內存
- 在字符串比較時,非駐留比較效率o(n),駐留時比較效率o(1)。
字符串什么時候駐留?
1.字符串只在編譯時進行駐留,而非運行時。
>>> a = "hello" + "world"
>>> a is "helloworld"
True
>>> a = "hello"
>>> b = "world"
>>> a + b is "helloworld"
False
2. 字符串長度為0和1時,默認都采用了駐留機制。
>>> a = "*"
>>> b = "*"
>>> a is b
True
>>> a = "**"
>>> b = "**"
>>> a is b
False
3. 字符串>1時,且只含大小寫字母、數字、下划線時,才會默認駐留。
>>> a = "hello1_"
>>> b = "hello1_"
>>> a is b
True
>>> a = "hello!"
>>> b = "hello!"
>>> a is b
False
4. 用乘法得到的字符串,有以下2種情況。
- a. 乘數為1時,詳見Python代碼:
# 乘數=1,僅含大小寫字母、數字、下划線駐留
>>> a = "abcdefghijklmnopqrstuvwxyz1234567890_ABCDXYZ"
>>> b = a * 1
>>> a is b
True
# 乘數=1,含其他字符,長度≤1,默認駐留
>>> a = "#"
>>> b = "#" * 1
>>> a is b
True
# 乘數=1,含其他字符,長度>1,則不駐留
>>> a = "##"
>>> b = "##" * 1
>>> a is b
False
- b.乘數>=2時,詳見Python代碼:
## 僅含有大小寫字母、數字、下划線,默認駐留
>>> a = "hellohellohellohellohellohellohello"
>>> b = "hello"*7
>>> a is b
True
# 含其他字符串,默認不駐留
>>> a = "&&&&"
>>> b = "&"*4
>>> a is b
False
5. 字符串被sys.intern() 指定駐留。
>>> from sys import intern
>>> a = intern("hello#!")
>>> b = intern("hello#!")
>>> a is b
True
>>>
最后,當不滿足標識符規則時,則不會啟用駐留機制,當然這只出現在命令行中,如果你使用pycharm
則不會出現這樣的情況,pycharm
內部已經幫我們做了處理