詳解Python中神奇的字符串駐留機(jī)制
今天有一個(gè)初學(xué)者在學(xué)習(xí)Python的時(shí)候又整不會(huì)了。 原因是以下代碼:
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")
運(yùn)行結(jié)果是a and b point to different objects。
然后他又試了字符串對(duì)象。
str1 = "hello" str2 = "hello" if str1 is str2: print("str1 and str2 are the same object") else: print("str1 and str2 are different objects")
運(yùn)行結(jié)果是:str1 and str2 are the same object
他找到田辛老師詢問(wèn)原因。 于是有了今天這篇文章:Python中的字符串駐留機(jī)制。
1 什么是字符串駐留機(jī)制
字符串駐留機(jī)制是Python針對(duì)字符串對(duì)象采取的一種內(nèi)存優(yōu)化技術(shù)。其目標(biāo)是減少內(nèi)存使用并提高程序的性能。
在Python中,字符串是不可變的對(duì)象,一旦創(chuàng)建,就不能被修改。因此,如果我們創(chuàng)建了兩個(gè)字符串,它們將占用兩個(gè)不同的內(nèi)存位置。但是,如果這些字符串是相同的,那么它們將被Python自動(dòng)合并為一個(gè)對(duì)象,這就是字符串駐留機(jī)制。
Python中的字符串駐留機(jī)制是通過(guò)使用intern機(jī)制來(lái)實(shí)現(xiàn)的。當(dāng)我們創(chuàng)建一個(gè)字符串時(shí),Python會(huì)檢查字符串池中是否已經(jīng)存在相同的字符串。如果是,它將返回現(xiàn)有的字符串對(duì)象的引用,而不是創(chuàng)建一個(gè)新的對(duì)象。這樣,我們可以在不占用額外內(nèi)存的情況下使用相同的字符串。
2 如何使用字符串駐留機(jī)制
Python的字符串駐留機(jī)制在不同版本之間有一些變化。下面是一些主要的變化:
1.Python 2.x和Python 3.x的字符串駐留機(jī)制不同。在Python 2.x中,只有長(zhǎng)度為1的字符串才會(huì)被駐留。而在Python 3.x中,長(zhǎng)度為0到20的字符串都會(huì)被駐留。 (更長(zhǎng)的田辛老師試過(guò),似乎都可以)
2.在Python 3.7之前,字符串駐留機(jī)制只適用于ASCII字符集中的字符串。這意味著只有ASCII字符集中的字符串才會(huì)被駐留。但是,在Python 3.7中,這個(gè)限制已經(jīng)被取消,所有字符串都可以被駐留。
3.在Python 3.8中,字符串駐留機(jī)制的實(shí)現(xiàn)發(fā)生了變化。在之前的版本中,字符串池是一個(gè)全局的數(shù)據(jù)結(jié)構(gòu),所有的字符串都存儲(chǔ)在其中。但是,在Python 3.8中,字符串池被改為了一個(gè)線程局部的數(shù)據(jù)結(jié)構(gòu),每個(gè)線程都有自己的字符串池。這樣可以提高多線程程序的性能。
需要注意的是,字符串駐留機(jī)制是Python的一種優(yōu)化技術(shù),它并不是Python語(yǔ)言規(guī)范的一部分。因此,不同的Python實(shí)現(xiàn)(如CPython、Jython、IronPython等)可能會(huì)有不同的字符串駐留機(jī)制實(shí)現(xiàn)。
正是因?yàn)樯厦娴淖兓?所以有的時(shí)候田辛老師覺(jué)得字符串駐留在面向內(nèi)存的時(shí)候是友好的, 但確實(shí)會(huì)給新手帶來(lái)一些不便。
作為新手, 田辛老師提供一個(gè)手動(dòng)使用字符串駐留的例子:
import sys # 使用sys.intern()函數(shù)啟用字符串駐留機(jī)制 str3 = sys.intern("hello") str4 = sys.intern("hello") # 使用is關(guān)鍵字比較兩個(gè)字符串是否相同 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。然后,我們?cè)俅问褂胕s關(guān)鍵字比較它們是否相同。由于它們是相同的對(duì)象,因此輸出結(jié)果為“str3 and str4 are the same object”。
3 簡(jiǎn)單拼接駐留, 運(yùn)行時(shí)不駐留
我們來(lái)看下面的代碼:
str5 = 'tianxin' + 'training' print(str5 is 'tianxintraining') str6 = 'tianxin' str7 = 'training' print((str6 + str7) is 'tianxintraining')
大家可以猜一猜輸出結(jié)果是什么? 是兩個(gè)true,還是一個(gè)true一個(gè)false?
答案是:
True
False
為什么會(huì)出現(xiàn)這種情況呢? 第一個(gè)打印,是兩個(gè)字符串簡(jiǎn)單拼接, 那么就會(huì)實(shí)現(xiàn)字符串駐留。 但是, 一旦是變量拼接字符串機(jī)制就不能用了。
關(guān)于這一點(diǎn), 田辛老師通過(guò)如下代碼帶領(lǐng)大家查看一下上述兩個(gè)處理的匯編執(zhí)行過(guò)程:
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的解釋器對(duì)這種簡(jiǎn)單的字符串拼接在形成字符碼的時(shí)候,就已經(jīng)進(jìn)行了拼接。 str5 你寫不寫成拼接的形式都是一樣的。
4 總結(jié)
Python的字符串駐留機(jī)制是一種優(yōu)化技術(shù),它可以減少內(nèi)存使用并提高程序的性能。它的做法的基礎(chǔ)是Python字符串對(duì)象的不可改變的特性。 當(dāng)然, 不同的Python版本對(duì)于字符串駐留機(jī)制的處理不同可能會(huì)給初學(xué)者帶來(lái)一些麻煩。 Python學(xué)習(xí)者必須要面對(duì)的一個(gè)問(wèn)題。
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 # # 代碼說(shuō)明 # #--------------------------------------------------------------------------""" 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)鍵字比較兩個(gè)字符串是否相同 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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python的簡(jiǎn)單web框架flask快速實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了python的簡(jiǎn)單web框架flask快速實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Pycharm中import?torch報(bào)錯(cuò),python中import?torch不報(bào)錯(cuò)的解決
這篇文章主要介紹了Pycharm中import?torch報(bào)錯(cuò),python中import?torch不報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01Python中高效的json對(duì)比庫(kù)deepdiff詳解
deepdiff模塊常用來(lái)校驗(yàn)兩個(gè)對(duì)象是否一致,包含3個(gè)常用類,DeepDiff,DeepSearch和DeepHash,其中DeepDiff最常用,可以對(duì)字典,可迭代對(duì)象,字符串等進(jìn)行對(duì)比,使用遞歸地查找所有差異,今天我們就學(xué)習(xí)一下快速實(shí)現(xiàn)代碼和文件對(duì)比的庫(kù)–deepdiff2022-07-07pyqt4教程之實(shí)現(xiàn)半透明的天氣預(yù)報(bào)界面示例
這篇文章主要介紹了pyqt4實(shí)現(xiàn)半透明的天氣預(yù)報(bào)界面示例,需要的朋友可以參考下2014-03-03關(guān)于python 讀取csv最快的Datatable的用法,你都學(xué)會(huì)了嗎
大家都知道Datatable與眾不同就是快,還有一點(diǎn)大家需要注意使用Datatable庫(kù)需要python3.6及以上版本,接下來(lái)通過(guò)本文給大家介紹了python 讀取csv最快的Datatable的用法,需要的朋友可以參考下2021-10-10Python爬蟲自動(dòng)化爬取b站實(shí)時(shí)彈幕實(shí)例方法
在本篇文章里小編給大家整理的是一篇關(guān)于Python爬蟲自動(dòng)化爬取b站實(shí)時(shí)彈幕實(shí)例方法,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01Linux下將Python的Django項(xiàng)目部署到Apache服務(wù)器
這篇文章主要介紹了Python的Django項(xiàng)目部署到Apache服務(wù)器上的要點(diǎn)總結(jié),文中針對(duì)的是wsgi連接方式,需要的朋友可以參考下2015-12-12