詳解Python中神奇的字符串駐留機(jī)制
今天有一個初學(xué)者在學(xué)習(xí)Python的時候又整不會了。 原因是以下代碼:
a = [1, 2, 3] b = [1, 2, 3] if a is b: print("a and b point to the same object") else: print("a and b point to different objects")
運行結(jié)果是a and b point to different objects。
然后他又試了字符串對象。
str1 = "hello" str2 = "hello" if str1 is str2: print("str1 and str2 are the same object") else: print("str1 and str2 are different objects")
運行結(jié)果是:str1 and str2 are the same object
他找到田辛老師詢問原因。 于是有了今天這篇文章:Python中的字符串駐留機(jī)制。
1 什么是字符串駐留機(jī)制
字符串駐留機(jī)制是Python針對字符串對象采取的一種內(nèi)存優(yōu)化技術(shù)。其目標(biāo)是減少內(nèi)存使用并提高程序的性能。
在Python中,字符串是不可變的對象,一旦創(chuàng)建,就不能被修改。因此,如果我們創(chuàng)建了兩個字符串,它們將占用兩個不同的內(nèi)存位置。但是,如果這些字符串是相同的,那么它們將被Python自動合并為一個對象,這就是字符串駐留機(jī)制。
Python中的字符串駐留機(jī)制是通過使用intern機(jī)制來實現(xiàn)的。當(dāng)我們創(chuàng)建一個字符串時,Python會檢查字符串池中是否已經(jīng)存在相同的字符串。如果是,它將返回現(xiàn)有的字符串對象的引用,而不是創(chuàng)建一個新的對象。這樣,我們可以在不占用額外內(nèi)存的情況下使用相同的字符串。
2 如何使用字符串駐留機(jī)制
Python的字符串駐留機(jī)制在不同版本之間有一些變化。下面是一些主要的變化:
1.Python 2.x和Python 3.x的字符串駐留機(jī)制不同。在Python 2.x中,只有長度為1的字符串才會被駐留。而在Python 3.x中,長度為0到20的字符串都會被駐留。 (更長的田辛老師試過,似乎都可以)
2.在Python 3.7之前,字符串駐留機(jī)制只適用于ASCII字符集中的字符串。這意味著只有ASCII字符集中的字符串才會被駐留。但是,在Python 3.7中,這個限制已經(jīng)被取消,所有字符串都可以被駐留。
3.在Python 3.8中,字符串駐留機(jī)制的實現(xiàn)發(fā)生了變化。在之前的版本中,字符串池是一個全局的數(shù)據(jù)結(jié)構(gòu),所有的字符串都存儲在其中。但是,在Python 3.8中,字符串池被改為了一個線程局部的數(shù)據(jù)結(jié)構(gòu),每個線程都有自己的字符串池。這樣可以提高多線程程序的性能。
需要注意的是,字符串駐留機(jī)制是Python的一種優(yōu)化技術(shù),它并不是Python語言規(guī)范的一部分。因此,不同的Python實現(xiàn)(如CPython、Jython、IronPython等)可能會有不同的字符串駐留機(jī)制實現(xiàn)。
正是因為上面的變化, 所以有的時候田辛老師覺得字符串駐留在面向內(nèi)存的時候是友好的, 但確實會給新手帶來一些不便。
作為新手, 田辛老師提供一個手動使用字符串駐留的例子:
import sys # 使用sys.intern()函數(shù)啟用字符串駐留機(jī)制 str3 = sys.intern("hello") str4 = sys.intern("hello") # 使用is關(guān)鍵字比較兩個字符串是否相同 if str3 is str4: print("str3 and str4 are the same object") else: print("str3 and str4 are different objects")
上面的例子中,田辛老師使用sys.intern()函數(shù)將字符串“hello”添加到字符串池中,并將返回的引用分配給str3和str4。然后,我們再次使用is關(guān)鍵字比較它們是否相同。由于它們是相同的對象,因此輸出結(jié)果為“str3 and str4 are the same object”。
3 簡單拼接駐留, 運行時不駐留
我們來看下面的代碼:
str5 = 'tianxin' + 'training' print(str5 is 'tianxintraining') str6 = 'tianxin' str7 = 'training' print((str6 + str7) is 'tianxintraining')
大家可以猜一猜輸出結(jié)果是什么? 是兩個true,還是一個true一個false?
答案是:
True
False
為什么會出現(xiàn)這種情況呢? 第一個打印,是兩個字符串簡單拼接, 那么就會實現(xiàn)字符串駐留。 但是, 一旦是變量拼接字符串機(jī)制就不能用了。
關(guān)于這一點, 田辛老師通過如下代碼帶領(lǐng)大家查看一下上述兩個處理的匯編執(zhí)行過程:
import dis def pro1(): str5 = 'tianxin' + 'training' print(str5 is 'tianxintraining') def pro2(): str6 = 'tianxin' str7 = 'training' print((str6 + str7) is 'tianxintraining') print('================================================================') dis.dis(pro1) print('================================================================') dis.dis(pro2)
輸出結(jié)果:
================================================================
20 0 LOAD_CONST 1 ('tianxintraining')
2 STORE_FAST 0 (str5)
21 4 LOAD_GLOBAL 0 (print)
6 LOAD_FAST 0 (str5)
8 LOAD_CONST 1 ('tianxintraining')
10 IS_OP 0
12 CALL_FUNCTION 1
14 POP_TOP
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
================================================================
25 0 LOAD_CONST 1 ('tianxin')
2 STORE_FAST 0 (str6)
26 4 LOAD_CONST 2 ('training')
6 STORE_FAST 1 (str7)
27 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (str6)
12 LOAD_FAST 1 (str7)
14 BINARY_ADD
16 LOAD_CONST 3 ('tianxintraining')
18 IS_OP 0
20 CALL_FUNCTION 1
22 POP_TOP
24 LOAD_CONST 0 (None)
26 RETURN_VALUE
進(jìn)程已結(jié)束,退出代碼0
我們可以看到, Python的解釋器對這種簡單的字符串拼接在形成字符碼的時候,就已經(jīng)進(jìn)行了拼接。 str5 你寫不寫成拼接的形式都是一樣的。
4 總結(jié)
Python的字符串駐留機(jī)制是一種優(yōu)化技術(shù),它可以減少內(nèi)存使用并提高程序的性能。它的做法的基礎(chǔ)是Python字符串對象的不可改變的特性。 當(dāng)然, 不同的Python版本對于字符串駐留機(jī)制的處理不同可能會給初學(xué)者帶來一些麻煩。 Python學(xué)習(xí)者必須要面對的一個問題。
5 全部代碼
上面已經(jīng)有了關(guān)于輸出匯編的全部代碼, 就不再重新輸出了。 只展示字符串駐留部分的代碼:
#!/usr/bin/env python # -*- coding:utf-8 -*- """ #----------------------------------------------------------------------------- # --- TDOUYA STUDIOS --- #----------------------------------------------------------------------------- # # @Project : di08-tdd-cdg-python-learning # @File : str_intern.py # @Author : tianxin.xp@gmail.com # @Date : 2023/4/5 10:34 # # 代碼說明 # #--------------------------------------------------------------------------""" import sys a = [1, 2, 3] b = [1, 2, 3] if a is b: print("a and b point to the same object") else: print("a and b point to different objects") str1 = "hello" str2 = "hello" if str1 is str2: print("str1 and str2 are the same object") else: print("str1 and str2 are different objects") # 使用sys.intern()函數(shù)啟用字符串駐留機(jī)制 str3 = sys.intern("hello") str4 = sys.intern("hello") # 使用is關(guān)鍵字比較兩個字符串是否相同 if str3 is str4: print("str3 and str4 are the same object") else: print("str3 and str4 are different objects") str5 = 'tianxin' + 'training' print(str5 is 'tianxintraining') str6 = 'tianxin' str7 = 'training' print((str6 + str7) is 'tianxintraining')
執(zhí)行結(jié)果:警告可忽略
D:\python-grp\miniconda_env\py3.10\python.exe E:\develop\python\di08-tdd-cdg-python-learning\src\std_str_intern\str_intern.py
a and b point to different objects
str1 and str2 are the same object
str3 and str4 are the same object
True
False
E:\develop\python\di08-tdd-cdg-python-learning\src\std_str_intern\str_intern.py:44: SyntaxWarning: "is" with a literal. Did you mean "=="?
print(str5 is 'tianxintraining')
E:\develop\python\di08-tdd-cdg-python-learning\src\std_str_intern\str_intern.py:48: SyntaxWarning: "is" with a literal. Did you mean "=="?
print((str6 + str7) is 'tianxintraining')
進(jìn)程已結(jié)束,退出代碼0
到此這篇關(guān)于詳解Python中神奇的字符串駐留機(jī)制的文章就介紹到這了,更多相關(guān)Python字符串駐留機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python的簡單web框架flask快速實現(xiàn)詳解
這篇文章主要為大家介紹了python的簡單web框架flask快速實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Pycharm中import?torch報錯,python中import?torch不報錯的解決
這篇文章主要介紹了Pycharm中import?torch報錯,python中import?torch不報錯的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01pyqt4教程之實現(xiàn)半透明的天氣預(yù)報界面示例
這篇文章主要介紹了pyqt4實現(xiàn)半透明的天氣預(yù)報界面示例,需要的朋友可以參考下2014-03-03關(guān)于python 讀取csv最快的Datatable的用法,你都學(xué)會了嗎
大家都知道Datatable與眾不同就是快,還有一點大家需要注意使用Datatable庫需要python3.6及以上版本,接下來通過本文給大家介紹了python 讀取csv最快的Datatable的用法,需要的朋友可以參考下2021-10-10Linux下將Python的Django項目部署到Apache服務(wù)器
這篇文章主要介紹了Python的Django項目部署到Apache服務(wù)器上的要點總結(jié),文中針對的是wsgi連接方式,需要的朋友可以參考下2015-12-12