国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

Python是否支持復(fù)制字符串呢?

aikin / 1616人閱讀

摘要:本文標(biāo)題的問(wèn)題分為兩部分中是否支持復(fù)制字符串如果不支持,為什么不支持請(qǐng)讀者花幾分鐘想一下,想清楚后,把你的答案記住,然后再往下看。什么是復(fù)制字符串首先,必須要大家對(duì)復(fù)制這個(gè)概念達(dá)成共識(shí)。

連續(xù)幾篇文章都在寫(xiě) Python 字符串,這出乎我的意料了。但是,有的問(wèn)題,不寫(xiě)不行,特別是那種靈機(jī)一動(dòng)想到的問(wèn)題,最后你發(fā)現(xiàn),很多人根本不懂卻又誤以為自己懂了。那就繼續(xù)刨根問(wèn)底,探究個(gè)明白吧。

在上一篇文章《你真的知道Python的字符串怎么用嗎?》里,我突發(fā)奇想,將字符串跟列表做了比較,然后發(fā)現(xiàn)字符串竟然沒(méi)有復(fù)制的方法。當(dāng)時(shí)沒(méi)有細(xì)想,只說(shuō)要擱置疑問(wèn)。過(guò)后,有好學(xué)的小伙伴在后臺(tái)留言,與我交流這個(gè)問(wèn)題,給了我一些啟發(fā)。為了徹底弄懂它,我繼續(xù)查了不少資料,今天,就跟大家分享一下我發(fā)現(xiàn)的東西吧。

本文標(biāo)題的問(wèn)題分為兩部分:(1)Python 中是否支持復(fù)制字符串?(2)如果不支持,為什么不支持?

請(qǐng)讀者花幾分鐘想一下,想清楚后,把你的答案記住,然后再往下看。

讓我們做一個(gè)約定(自愿遵守):如果看到最后,你推翻了現(xiàn)在的答案,建立了新的認(rèn)知,這說(shuō)明我寫(xiě)的內(nèi)容有用,那請(qǐng)你任意贊賞,或者將本文分享給其他使用 Python 的小伙伴。

1. 什么是復(fù)制字符串?

首先,必須要大家對(duì)“復(fù)制”這個(gè)概念達(dá)成共識(shí)。復(fù)制,也叫拷貝,英文單詞是 copy,具體意思是“將某事物通過(guò)某種方式制作成相同的一份或多份的行為”(釋義來(lái)自維基百科)。復(fù)制的結(jié)果是,出現(xiàn)了多份極其相似但卻相互獨(dú)立的事物(副本),舉例來(lái)說(shuō),你有一份文檔 X,然后復(fù)制一份并重新命名為 Y,這兩者是相互獨(dú)立的,若你刪除其中一個(gè),另一個(gè)不會(huì)一起被刪除。

這個(gè)詞用在 Python 里,我們想表達(dá)的是同樣的意思,即復(fù)制行為會(huì)產(chǎn)生新的獨(dú)立對(duì)象,它與原始對(duì)象極其相似,但兩者的生命周期沒(méi)有直接的關(guān)聯(lián)關(guān)系。下面先用列表來(lái)舉例:

list1 = [1,2]
id(list1) 
>>> 1981119454856

list2 = list1.copy()
print(list1 == list2) 
>>> True
id(list2)
>>> 1981116983752

上例中,列表 list2 是 list1 的副本,兩者字面量相等,但是內(nèi)存地址(即 id )不相等,是兩個(gè)相互獨(dú)立的對(duì)象。如果字符串能夠做到同樣的效果,那我們就說(shuō),字符串可以被復(fù)制,否則,我們說(shuō)字符串不可以被復(fù)制。

2. 怎樣能復(fù)制字符串?

有了上面的概念和示例,請(qǐng)先思考,你會(huì)用什么方式復(fù)制字符串呢?(暫停,思考3分鐘)

好了,先看看下面的幾種方法:

s0 = "Python貓"

s1 = s0
s2 = str(s0)
s3 = s0[:]
s4 = s0 + ""
s5 = "%s" % s0
s6 = s0 * 1
s7 = "".join(s0)
import copy
s8 = copy.copy(s0)

你想到的復(fù)制方式是否在以上8種方式里呢?那么,如果把 s0 至 s8 的 id 打印出來(lái),有哪些會(huì)跟 s0 不同呢?

答案是,它們的內(nèi)存地址 id 完全相同,也就是說(shuō),一頓操作猛如虎,結(jié)果卻始終只有一份字符串,根本沒(méi)有復(fù)制出新的字符串!

Python貓 的老讀者看到這,會(huì)心一笑,這不就是因?yàn)樽址?Intern 機(jī)制嘛,短字符串在內(nèi)存中只會(huì)存在一份,在《Python中的“特權(quán)種族”是什么?》這篇文章里提到過(guò)的。

但請(qǐng)別開(kāi)心得太早,你可以把 s0 改成一個(gè)超長(zhǎng)的字符串,例如:

s0 = "Python貓是來(lái)自喵星的客人,它喜歡地球和人類(lèi),正在學(xué)習(xí)Python,而且想借助Python變成人,它的微信公眾號(hào)也叫Python貓,歡迎你關(guān)注哦,喵喵喵喵~~~"

然后,再重復(fù)上面的操作。最終,你會(huì)發(fā)現(xiàn),s0 到 s8 的 id 還是完全相同。

是不是吃驚了呢?新的 s0 明明已經(jīng)超過(guò) Intern 機(jī)制的長(zhǎng)度了,為什么不會(huì)產(chǎn)生新的字符串呢?

首先,請(qǐng)你相信,超出 Intern 機(jī)制的字符串可以存在多份,即你可以創(chuàng)建出值完全相同的多個(gè)字符串對(duì)象,因?yàn)樽址畬?duì)象在內(nèi)存中并不一定是唯一的:

s9 = "Python貓是來(lái)自喵星的客人,它喜歡地球和人類(lèi),正在學(xué)習(xí)Python,而且想借助Python變成人,它的微信公眾號(hào)也叫Python貓,歡迎你關(guān)注哦,喵喵喵喵~~~"

print(id(s0) == id(s9))
>>> False 

上例表明,你可以創(chuàng)建出多個(gè)相同的字符串對(duì)象,但是這種方法與前面列舉的8種不同,因?yàn)樗仟?dú)立于 s0 的操作,并不是一種復(fù)制操作。從理論上講,Python 完全可以提供一個(gè)方法,達(dá)到復(fù)制出新的副本的結(jié)果。現(xiàn)在的問(wèn)題恰恰就是:為什么允許存在多個(gè)相等的字符串對(duì)象,但是卻無(wú)法通過(guò)復(fù)制的方式來(lái)創(chuàng)建呢?

3. 為什么不允許復(fù)制字符串?

我發(fā)現(xiàn),不僅字符串不允許復(fù)制,元祖也如此,事實(shí)上,還有 int 、float 也不支持復(fù)制。它們都是不可變對(duì)象,為什么不可變對(duì)象就不支持復(fù)制操作呢?

在查資料的時(shí)候,我發(fā)現(xiàn)網(wǎng)上很多文章對(duì)于“不可變對(duì)象”的認(rèn)識(shí)存在誤區(qū),這些人不知道 Intern 機(jī)制的存在,誤以為字符串對(duì)象在內(nèi)存只能有唯一一個(gè),進(jìn)而誤以為不可變對(duì)象就是在內(nèi)存中只有一份的對(duì)象。所以,這些文章很容易推斷出錯(cuò)誤的結(jié)論:因?yàn)樽址遣豢勺儗?duì)象,所以字符串不支持復(fù)制。

事實(shí)上,不可變對(duì)象跟復(fù)制操作之間,并沒(méi)有必然的強(qiáng)相關(guān)的關(guān)系。肯定是出于別的原因,設(shè)計(jì)者才給不可變對(duì)象加上這種限制,這個(gè)原因是什么呢?

在知乎上,有敏銳的同學(xué)提出了我的疑問(wèn)“Python中如何復(fù)制一個(gè)值或字符串?”,可惜只有4個(gè)回答,而且都沒(méi)答到點(diǎn)上。Stackoverflow上恰好也有一個(gè)問(wèn)題“How can I copy a Python string?”,同樣沒(méi)多少人注意到,只有5個(gè)回答,好在最高票答案提到了一個(gè)點(diǎn),即這樣可以加快字典的查找速度。

然而,他說(shuō)的這個(gè)點(diǎn)并不靠譜。字典要求鍵值是可哈希對(duì)象,可是計(jì)算字符串的哈希值是根據(jù)字面值計(jì)算,所以對(duì)多個(gè)相等的字符串對(duì)象,其哈希值其實(shí)是一樣的,對(duì)計(jì)算和查找根本無(wú)影響。

w1 = "Python貓是來(lái)自喵星的客人,它喜歡地球和人類(lèi),正在學(xué)習(xí)Python,而且想借助Python變成人,它的微信公眾號(hào)也叫Python貓,歡迎你關(guān)注哦,喵喵喵喵~~~"
w2 = "Python貓是來(lái)自喵星的客人,它喜歡地球和人類(lèi),正在學(xué)習(xí)Python,而且想借助Python變成人,它的微信公眾號(hào)也叫Python貓,歡迎你關(guān)注哦,喵喵喵喵~~~"

print(w1 == w2) 
>>> True
print(id(w1) == id(w2)) 
>>> False 
print(hash(w1) == hash(w2)) 
>>> True

繼續(xù)查資料,終于在《流暢的Python》找到了明確的解釋?zhuān)?/p>

這些細(xì)節(jié)是 CPython 核心開(kāi)發(fā)者走的捷徑和做的優(yōu)化措施,對(duì)這門(mén)語(yǔ)言的用戶(hù)而言無(wú)需了解,而且那些細(xì)節(jié)對(duì)其他 Python 實(shí)現(xiàn)可能沒(méi)用,CPython 未來(lái)的版本可能也不會(huì)用。

這本《流暢的Python》是進(jìn)階首選書(shū)目之一,我曾讀過(guò)部分章節(jié),沒(méi)想到在一個(gè)不起眼的小節(jié)里,作者 “驚訝地發(fā)現(xiàn)” 元祖的不可復(fù)制性,在此之前,他還自以為“對(duì)元祖無(wú)所不知”,哈哈哈。

雖然,我早猜測(cè)到原因是節(jié)省內(nèi)存和提高速度,但看到這個(gè)明確的解釋?zhuān)肋@只是CPython 解釋器的“善意的謊言”,而且在未來(lái)版本可能不會(huì)用,我感到特別意外。

它證實(shí)了我的猜測(cè),同時(shí),也提供了超預(yù)期的信息:其它 Python 解釋器可能支持復(fù)制不可變對(duì)象,目前 CPython 算是一種妥協(xié),在未來(lái)可能會(huì)恢復(fù)不可變對(duì)象的復(fù)制操作呢!

回到文章開(kāi)頭的兩個(gè)問(wèn)題,我們得到的答案是:Python 本身并不限制字符串的復(fù)制操作,只是當(dāng)前版本的 CPython 做了優(yōu)化,才導(dǎo)致出現(xiàn)這種“善意的謊言”,它這么做的原因?yàn)榱藢?duì) Intern 機(jī)制做補(bǔ)充,設(shè)法使全部字符串對(duì)象在內(nèi)存都只有一份,以達(dá)到節(jié)省內(nèi)存的效果。

CPython 是用 C 語(yǔ)言實(shí)現(xiàn)的 Python 解釋器,是官方的、使用最廣泛的解釋器。除了它,還有用 Java 實(shí)現(xiàn)的 Jython 解釋器、用 .NET 實(shí)現(xiàn)的 IronPython 解釋器、用 Python 實(shí)現(xiàn)的 PyPy 解釋器,等等。其它解釋器都是怎么應(yīng)對(duì)字符串的復(fù)制操作的呢?唉,學(xué)無(wú)止境,本人才疏學(xué)淺沒(méi)有涉獵,還是先擱置疑問(wèn)吧。

這里,我就想提一個(gè)題外話(huà),Python 最最最廣為人詬病的就是 GIL(全局解釋器鎖),這導(dǎo)致它不支持真正意義的多線(xiàn)程,成為很多人指責(zé) Python 慢的元兇。但是,這個(gè)問(wèn)題是 CPython 解釋器帶來(lái)的,而像 Jython 解釋器就不存在這個(gè)問(wèn)題。

好了,就此打住吧。你是否還記得在文章開(kāi)頭時(shí)想到的答案呢?是否改變了最初的想法呢?歡迎關(guān)注公眾號(hào) Python貓 ,來(lái)跟我交流,一起來(lái)學(xué)習(xí) Python ,做個(gè)合格的 Pythonista

參考學(xué)習(xí):

《流暢的Python》

https://www.zhihu.com/questio...

https://dwz.cn/4o0WXy8G

最后是福利時(shí)刻:本公眾號(hào)(Python貓)由清華大學(xué)出版社贊助,將抽獎(jiǎng)送出兩本新書(shū)《深入淺出Python機(jī)器學(xué)習(xí)》,截止時(shí)間到11月29日18:18,點(diǎn)擊 這個(gè)鏈接,馬上參與吧。

本文原創(chuàng)并首發(fā)于微信公眾號(hào)【Python貓】,后臺(tái)回復(fù)“愛(ài)學(xué)習(xí)”,免費(fèi)獲得20+本精選電子書(shū)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/72462.html

相關(guān)文章

  • Python是否支持復(fù)制符串

    摘要:本文標(biāo)題的問(wèn)題分為兩部分中是否支持復(fù)制字符串如果不支持,為什么不支持請(qǐng)讀者花幾分鐘想一下,想清楚后,把你的答案記住,然后再往下看。什么是復(fù)制字符串首先,必須要大家對(duì)復(fù)制這個(gè)概念達(dá)成共識(shí)。 showImg(https://segmentfault.com/img/bVbkgbP?w=4147&h=2765); 連續(xù)幾篇文章都在寫(xiě) Python 字符串,這出乎我的意料了。但是,有的問(wèn)題,不...

    Jiavan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

aikin

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<