成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Python是否支持復制字符串呢?

aikin / 1625人閱讀

摘要:本文標題的問題分為兩部分中是否支持復制字符串如果不支持,為什么不支持請讀者花幾分鐘想一下,想清楚后,把你的答案記住,然后再往下看。什么是復制字符串首先,必須要大家對復制這個概念達成共識。

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

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

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

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

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

1. 什么是復制字符串?

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

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

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

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

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

2. 怎樣能復制字符串?

有了上面的概念和示例,請先思考,你會用什么方式復制字符串呢?(暫停,思考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)

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

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

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

但請別開心得太早,你可以把 s0 改成一個超長的字符串,例如:

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

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

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

首先,請你相信,超出 Intern 機制的字符串可以存在多份,即你可以創(chuàng)建出值完全相同的多個字符串對象,因為字符串對象在內(nèi)存中并不一定是唯一的:

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

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

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

3. 為什么不允許復制字符串?

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

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

事實上,不可變對象跟復制操作之間,并沒有必然的強相關(guān)的關(guān)系??隙ㄊ浅鲇趧e的原因,設(shè)計者才給不可變對象加上這種限制,這個原因是什么呢?

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

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

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

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

繼續(xù)查資料,終于在《流暢的Python》找到了明確的解釋:

這些細節(jié)是 CPython 核心開發(fā)者走的捷徑和做的優(yōu)化措施,對這門語言的用戶而言無需了解,而且那些細節(jié)對其他 Python 實現(xiàn)可能沒用,CPython 未來的版本可能也不會用。

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

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

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

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

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

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

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

參考學習:

《流暢的Python》

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

https://dwz.cn/4o0WXy8G

最后是福利時刻:本公眾號(Python貓)由清華大學出版社贊助,將抽獎送出兩本新書《深入淺出Python機器學習》,截止時間到11月29日18:18,點擊 這個鏈接,馬上參與吧。

本文原創(chuàng)并首發(fā)于微信公眾號【Python貓】,后臺回復“愛學習”,免費獲得20+本精選電子書。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/72462.html

相關(guān)文章

  • Python是否支持復制符串?

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

    Jiavan 評論0 收藏0

發(fā)表評論

0條評論

aikin

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<