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

栏目: Python · 发布时间: 6年前

内容简介:连续几篇文章都在写 Python 字符串,这出乎我的意料了。但是,有的问题,不写不行,特别是那种灵机一动想到的问题,最后你发现,在上一篇文章《本文标题的问题分为两部分:(1)Python 中是否支持复制字符串?(2)如果不支持,为什么不支持?

连续几篇文章都在写 Python 字符串,这出乎我的意料了。但是,有的问题,不写不行,特别是那种灵机一动想到的问题,最后你发现, 很多人根本不懂却又误以为自己懂了 。那就继续刨根问底,探究个明白吧。

在上一篇文章《 你真的知道Python的字符串怎么用吗? 》里,我突发奇想,将字符串跟列表做了比较,然后发现字符串竟然没有复制的方法。当时没有细想,只说要搁置疑问。过后,有好学的小伙伴在后台留言,与我交流这个问题,给了我一些启发。为了彻底弄懂它,我继续查了不少资料,今天,就跟大家分享一下我发现的东西吧。

本文标题的问题分为两部分:(1)Python 中是否支持复制字符串?(2)如果不支持,为什么不支持?

请读者花几分钟想一下,想清楚后,把你的答案记住,然后再往下看。

让我们做一个约定(自愿遵守):如果看到最后,你推翻了现在的答案,建立了新的认知,这说明我写的内容有用,那请你任意赞赏,或者将本文分享给其他使用 Python 的小伙伴。

1. 什么是复制字符串?

首先,必须要大家对“复制”这个概念达成共识。复制,也叫 拷贝 ,英文单词是 copy,具体意思是“ 将某事物通过某种方式制作成相同的一份或多份的行为 ”(释义来自维基百科)。复制的结果是,出现了多份极其相似但却相互独立的事物(副本),举例来说,你有一份文档 X,然后复制一份并重新命名为 Y,这两者是相互独立的,若你删除其中一个,另一个不会一起被删除。

这个词用在 Python 里,我们想表达的是同样的意思,即复制行为会产生新的独立对象,它与原始对象极其相似,但两者的生命周期没有直接的关联关系。下面先用列表来举例:

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

list2 = list1.copy()
print(list1 == list2) 
>>> True
id(list2)
>>> 1981116983752
复制代码

上例中,列表 list2 是 list1 的副本,两者字面量相等,但是内存地址(即 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 不同呢?

答案是, 它们的内存地址 id 完全相同 ,也就是说,一顿操作猛如虎,结果却始终只有一份字符串,根本没有复制出新的字符串!

Python猫 的老读者看到这,会心一笑,这不就是因为字符串的 Intern 机制嘛,短字符串在内存中只会存在一份,在《 Python中的“特权种族”是什么? 》这篇文章里提到过的。

但请别开心得太早,你可以把 s0 改成一个超长的字符串,例如:

s0 = "Python猫是来自喵星的客人,它喜欢地球和人类,正在学习Python,而且想借助Python变成人,它的微信公众号也叫Python猫,欢迎你关注哦,喵喵喵喵~~~~~~~"

然后,再重复上面的操作。最终,你会发现,s0 到 s8 的 id 还是完全相同。

是不是吃惊了呢?新的 s0 明明已经超过 Intern 机制的长度了,为什么不会产生新的字符串呢?

首先,请你相信, 超出 Intern 机制的字符串可以存在多份 ,即你可以创建出值完全相同的多个字符串对象,因为字符串对象在内存中并不一定是唯一的:

s9 = "Python猫是来自喵星的客人,它喜欢地球和人类,正在学习Python,而且想借助Python变成人,它的微信公众号也叫Python猫,欢迎你关注哦,喵喵喵喵~~~"

print(id(s0) == id(s9))
>>> False 
复制代码

上例表明,你可以创建出多个相同的字符串对象,但是这种方法与前面列举的8种不同,因为它是独立于 s0 的操作,并不是一种复制操作。从理论上讲,Python 完全可以提供一个方法,达到复制出新的副本的结果。现在的问题恰恰就是: 为什么允许存在多个相等的字符串对象,但是却无法通过复制的方式来创建呢?

3. 为什么不允许复制字符串?

我发现,不仅字符串不允许复制,元祖也如此,事实上,还有 int 、float 也不支持复制。它们都是不可变对象,为什么不可变对象就不支持复制操作呢?

在查资料的时候,我发现网上很多文章对于“不可变对象”的认识存在误区,这些人不知道 Intern 机制的存在,误以为字符串对象在内存只能有唯一一个,进而误以为不可变对象就是在内存中只有一份的对象。所以,这些文章很容易推断出错误的结论:因为字符串是不可变对象,所以字符串不支持复制。

事实上,不可变对象跟复制操作之间,并没有必然的强相关的关系。肯定是出于别的原因,设计者才给不可变对象加上这种限制,这个原因是什么呢?

在知乎上,有敏锐的同学提出了我的疑问“ Python中如何复制一个值或字符串? ”,可惜只有4个回答,而且都没答到点上。Stackoverflow上恰好也有一个问题“ How can I copy a Python string? ”,同样没多少人注意到,只有5个回答,好在最高票答案提到了一个点,即这样可以加快字典的查找速度。

然而,他说的这个点并不靠谱。字典要求键值是可哈希对象,可是计算字符串的哈希值是根据字面值计算,所以对多个相等的字符串对象,其哈希值其实是一样的,对计算和查找根本无影响。

w1 = "Python猫是来自喵星的客人,它喜欢地球和人类,正在学习Python,而且想借助Python变成人,它的微信公众号也叫Python猫,欢迎你关注哦,喵喵喵喵~~~"
w2 = "Python猫是来自喵星的客人,它喜欢地球和人类,正在学习Python,而且想借助Python变成人,它的微信公众号也叫Python猫,欢迎你关注哦,喵喵喵喵~~~"

print(w1 == w2) 
>>> True
print(id(w1) == id(w2)) 
>>> False 
print(hash(w1) == hash(w2)) 
>>> True
复制代码

继续查资料,终于在《流畅的Python》找到了明确的解释:

这些细节是 CPython 核心开发者走的捷径和做的优化措施,对这门语言的用户而言无需了解,而且那些细节对其他 Python 实现可能没用,CPython 未来的版本可能也不会用。

这本《流畅的Python》是进阶首选书目之一,我曾读过部分章节,没想到在一个不起眼的小节里,作者 “惊讶地发现” 元祖的不可复制性,在此之前,他还自以为“对元祖无所不知”,哈哈哈。

虽然,我早猜测到原因是节省内存和提高速度,但看到这个明确的解释,知道这只是CPython 解释器的“善意的谎言”,而且在未来版本可能不会用,我感到特别意外。

它证实了我的猜测,同时,也提供了超预期的信息: 其它 Python 解释器可能支持复制不可变对象,目前 CPython 算是一种妥协,在未来可能会恢复不可变对象的复制操作呢!

回到文章开头的两个问题,我们得到的答案是: Python 本身并不限制字符串的复制操作,只是当前版本的 CPython 做了优化,才导致出现这种“善意的谎言”,它这么做的原因为了对 Intern 机制做补充,设法使全部字符串对象在内存都只有一份,以达到节省内存的效果。

CPython 是用 C 语言实现的 Python 解释器,是官方的、使用最广泛的解释器。除了它,还有用 Java 实现的 Jython 解释器、用 .NET 实现的 IronPython 解释器、用 Python 实现的 PyPy 解释器,等等。其它解释器都是怎么应对字符串的复制操作的呢?唉,学无止境,本人才疏学浅没有涉猎,还是先搁置疑问吧。

这里,我就想提一个题外话,Python 最最最广为人诟病的就是 GIL(全局解释器锁),这导致它不支持真正意义的多线程,成为很多人指责 Python 慢的元凶。但是,这个问题是 CPython 解释器带来的,而像 Jython 解释器就不存在这个问题。

好了,就此打住吧。你是否还记得在文章开头时想到的答案呢?是否改变了最初的想法呢?欢迎关注公众号 Python猫 ,来跟我交流,一起来学习 Python ,做个合格的 Pythonista

参考学习:

《流畅的Python》

www.zhihu.com/question/41…

dwz.cn/4o0WXy8G

最后是福利时刻:本公众号( Python猫 )由清华大学出版社赞助,将抽奖送出两本新书《深入浅出Python机器学习》,截止时间到11月29日18:18,点击这个链接,马上参与吧。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ajax Design Patterns

Ajax Design Patterns

Michael Mahemoff / O'Reilly Media / 2006-06-29 / USD 44.99

Ajax, or Asynchronous JavaScript and XML, exploded onto the scene in the spring of 2005 and remains the hottest story among web developers. With its rich combination of technologies, Ajax provides a s......一起来看看 《Ajax Design Patterns》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具