詳解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 你寫(xiě)不寫(xiě)成拼接的形式都是一樣的。
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對(duì)mysql表做全局模糊搜索并分頁(yè)實(shí)例
這篇文章主要介紹了利用python對(duì)mysql表做全局模糊搜索并分頁(yè)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
pyecharts如何旋轉(zhuǎn)折線圖的X軸標(biāo)簽
這篇文章主要介紹了pyecharts如何旋轉(zhuǎn)折線圖的X軸標(biāo)簽,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
對(duì)python過(guò)濾器和lambda函數(shù)的用法詳解
今天小編就為大家分享一篇對(duì)python過(guò)濾器和lambda函數(shù)的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
python/golang實(shí)現(xiàn)循環(huán)鏈表的示例代碼
這篇文章主要介紹了python/golang如何實(shí)現(xiàn)循環(huán)鏈表,幫助大家更好的理解和學(xué)習(xí)循環(huán)鏈表的實(shí)現(xiàn)方法,感興趣的朋友可以了解下2020-09-09
Python3.6通過(guò)自帶的urllib通過(guò)get或post方法請(qǐng)求url的實(shí)例
下面小編就為大家分享一篇Python3.6通過(guò)自帶的urllib通過(guò)get或post方法請(qǐng)求url的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
利用Python實(shí)現(xiàn)批量打包程序的工具
auto-py-to-exe與pyinstaller都無(wú)法直接一次性打包多個(gè)程序,想打包多個(gè)程序需要重新操作一遍。所以本文將用Python實(shí)現(xiàn)批量打包程序的工具,感興趣的可以了解一下2022-07-07
Matplotlib可視化之添加讓統(tǒng)計(jì)圖變得簡(jiǎn)單易懂的注釋
今天給大家?guī)?lái)的文章是關(guān)于Python的,文章圍繞著Python Matplotlib可視化展開(kāi),文中非常詳細(xì)的介紹了如何給統(tǒng)計(jì)圖添加注釋,需要的朋友可以參考下2021-06-06
Python爬蟲(chóng)獲取整個(gè)站點(diǎn)中的所有外部鏈接代碼示例
這篇文章主要介紹了Python爬蟲(chóng)獲取整個(gè)站點(diǎn)中的所有外部鏈接代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12

