Python中有效的字符串合并方法

上传人:平*** 文档编号:12790798 上传时间:2017-10-20 格式:DOCX 页数:7 大小:108.26KB
返回 下载 相关 举报
Python中有效的字符串合并方法_第1页
第1页 / 共7页
Python中有效的字符串合并方法_第2页
第2页 / 共7页
Python中有效的字符串合并方法_第3页
第3页 / 共7页
Python中有效的字符串合并方法_第4页
第4页 / 共7页
Python中有效的字符串合并方法_第5页
第5页 / 共7页
点击查看更多>>
资源描述

《Python中有效的字符串合并方法》由会员分享,可在线阅读,更多相关《Python中有效的字符串合并方法(7页珍藏版)》请在金锄头文库上搜索。

1、Python 中有效的字符串合并方法介绍在 Python 编程语言中,构造一些较长的字符串事常常会产生一些运行很慢的代码。本文我将研究不同字符串合并方法的计算性能。在 Python 中,字符串(string)对象是不可变的(每次关联一个新的字符串变量都会在内存中创建一个新的对象)(译注:类同于 Java,.NET 等现代语言,他们都会在其 VM 中保留一个字符串池,里面保存所有产生的目标字符串值或临时字符串值)。这方面它与 perl、VB 等语言中的字符串变量可以任意修改有所不同。如果使用一些比较显而易见的方法(比如:每次都是在新产生的字符串末尾添加一个新短字符串片段)从一些短字符串片段构造长

2、字符串在 Python 中可能会不是很有效率。每次你的在字符串末尾添加内容,Python 解释器都会创建一个新的对象并且复制新产生的对象和原来的对象到解释器中(译注:应该是复制到 Python 解释器的字符串常量池中) 。随着处理的字符串的增多,这样的处理过程将会越来越慢。其他一些其他的方法呢?他们是否有效并且与原始方法相比它们性能方面如何?我决定试试一些其他的构造长字符串的方法,并看看它们在效率上都有啥不同。为了比较,我需要一个测试程序来调用大量的字符串片段构造长字符串。它不应该有太多的额外计算,好让我们测试的性能仅仅依赖于字符串操作的性能。我的测试用例是合并一些从 0 到某个大整数的数字。

3、这样我们也可以很容易的改变需要产生字符串的大小(译注: 改变那个大整数) 。比如前 20 个整数产生如下的字符串:0123456789010111213141516171819尽管这个特别的测试问题不会有任何的现实应用,但我想,因为它很容易编程并且在概念和计算上都简单,那么它能是一个很好的测试用例。这些字符串片段在值和长度上都不同,这也可以防止解释器或硬件对依赖于重复字节的优化(译注:比如对重复相同的字符串进行压缩等处理)。我不认为 Python 解释器真的这样做了,但是作为测试的一个好原则就是不能受这种优化情况的影响。六个方法下面是我测试的一些方法,每小段 Python 代码都返回相同的字符

4、串。方法一:朴素的添加(Method 1: Naive appending)def method1():out_str = for num in xrange(loop_count):out_str += numreturn out_str对于我来说,这是解决该问题的最显而易见的方法。使用字符串连接操作(+=)添加每个字符串片段到字符串中。loop_count 告诉我们要添加的字符串片段数。第四行中的数字 num 两边的重音符()会把整数转换为相对于的字符串。你可以使用 str()方法完成一样的功能,但是,比较起来它可能稍慢些,因此我所有的方法中都是使用重音符()。如我说言,尽管很浅显,但是这

5、个方法根本不是很有效(译注:maybe 应该加个”率” 子) 。你可以再下面的测试中看到它每秒仅仅能合并 3770 个字符串片段。如果你需要合并很多的字符串片段,那么这可能不是很好的解决方法。方法二:MutableString 类(Method 2: MutableString class)def method2():from UserString import MutableStringout_str = MutableString()for num in xrange(loop_count):out_str += numreturn out_strPython 类库中包括一个 Mutabl

6、eString 类。根据其文档描述它主要用于教学目的(译注 : mutable string objects Python strings are immutable objects. This has the advantage, that strings may be used as dictionary keys. If this property isnt needed and you insist on changing string values in place instead, you may cheat and use MutableString. But the purpo

7、se of this class is an educational one: to prevent people from inventing their own mutable string class derived from UserString and than forget thereby to remove (override) the _hash_ method inherited from UserString. This would lead to errors that would be very hard to track down. A faster and bett

8、er solution is to rewrite your program using lists.)。你可以能会以为在一个可变字符串上添加操作不会从分配或者拷贝字符串(译注:本来该类应该很像 Java 的 StringBuilder 的)。但是在测试中该方法比方法 1 还差。通过查看 UserString.py 的源代码我发现字符串在 MutableString 中的存储就是 string,MutableString 甚至都没重写_add_方法。所以使用该类对象合并字符串不会比一般的不可变字符串更快,实际上由于解释MutableString 方法需要一些额外的开销会使得该方法更慢。方法三:

9、字符数组(Method 3: Character arrrays)def method3():from array import arraychar_array = array(c)for num in xrange(loop_count):char_array.fromstring(num)return char_array.tostring()我几乎都没有尝试这种方法,但是邮件列表中有人提到了,所以我决定试试。该方法的思想就是用字符数组存储字符串。Python 中的数组是可变的,所以它可以被原地改变(译注:也就是在该对象的那块内存上进行改变,而不需要通过复制到其他的空间上实现)而不需要拷贝

10、现存的数组内容。这里我们对改变现存的数组元素没有兴趣。我们只是在数组末尾添加一些新的数组元素。fromstring()方法一个字符一个字符的添加字符串字符到字符数组对象中。方法四:构造一个字符串列表,然后 join 它(Method 4: Build a list of strings, then join it)def method4():str_list = for num in xrange(loop_count):str_list.append(num)return .join(str_list)这是一种通常被推荐的方法,因为它的字符串合并方法很 Python。首先构造一个包含所有需要

11、合并的字符串列表,然后使用一个字符串的 join 操作构造包含所有列表元素的字符串。这人有点好玩,看看 python 习语的最后一行-我们在确定的空字符串上调用join 方法。不是所有的语言都会让你在一个字面上的字符串调用方法(译注:这里的意识是是空字符串)。如果你觉得这儿有点不爽,你可以写成如下形式 : string.join(str_list, )。方法五:写到一个伪文件中去(Method 5: Write to a pseudo file)def method5():from cStringIO import StringIOfile_str = StringIO()for num in

12、 xrange(loop_count):file_str.write(num)return file_str.getvalue()cStringIO 模块提供的 StringIO 类可以像文件一样工作,但是它存储为一个字符串。很明显,添加内容到文件中是很容易的你可以简单的写入到文件末尾,对 StringIO 类对象的操作也是一样。还有一个相似的模块叫 StringIO, 不过它是以 Python 实现的,而 cStringIO 是用 C 实现的,所以 cStringIO速度上会更快。使用 cStringIO 对象,我么可以构造一个每次写入一次内容的字符串,然后通过调用 getvalue()方法

13、收集其中的所有内容。有意思的是,同 python 类似,在 java 中字符串也是不可变的对象。Java 中有个类叫 StringBuffer,它比 python 中的 StringIO 和数组方法都更加强大,因为它不仅支持添加字符串还支持插入和删除子字符串操作。方法六:列表推导 (Method 6: List comprehensions)def method6():return .join(num for num in xrange(loop_count)方法的代码是最短的。并且令人惊喜的是他也是最快的。它及其紧凑并且也非常好理解。使用列表推导创建一个列表并使用 join 方法合并它们。还

14、如比这个简单的吗?实际上这是方法 4 的简略版,当然,它也需要消耗差不多的空间。它更快是因为不需要在循环的每次都调用 list.append()方法。测试结果我想要查看合并字符串时所花费的时间和计算时 Python 解释器的内存使用情况。尽管内存很便宜(译注: 这里应该是内存开销不是非常大的意思) ,但是依然有很多原因使其成为一个重要的因素。首先,Python 程序常常会运行在资源受限的系统上。例如,在一个共享虚拟主机的环境下,机器可能对每个进程设置了一定大小的内存使用。系统内核往往会杀死内存分配超过一定额度的进程。这种情况对于一些 CGI 脚本 (译注: Computer Graphics

15、Interface),长时运行的服务器程序来说将是不好的现象。所以在这种情况下,保存内存使用不超过预期是很重要的。另一个原因是当我们处理大量的字符串的时候,解释器的内存分配将会变得非常大可能会导致虚拟内存的访问(译注:paging 是操作系统中的一个概念,表示对硬盘页面的访问)。这种情况下的性能将会直线下降。如果你发现了时间上最快的算法当然无所谓了-如果它使用了过多的内存将会允许得和狗(译注: 应该是像蜗牛吧 ,J)一样慢。如果用的算法使用更少的内存,那么就会介绍 paging 的机会,我们也将会有更多的可预测性能。我使用自己的 Python 过程分别测试每种方法。我在一台按照了 FreeBS

16、D 4.9 的 433MHz PII Celeron 机器上使用 Python 2.2.1 运行这些测试程序。结果:两万个整数(Results: Twenty thousand integers)第一个测试将两万个整数合并成一个 86kb 大小的字符串。结果:五十万个整数(Results: Five hundred thousand integers)接下来我测试了将五十万个整数合并成一个 2,821kb 大小的字符串。这个测试更严厉,我们开始想看看 Python 解释器进程的使用资源大小随着用于计算的数据结构变化情况。这个测试中我没有运行方法 1 和方法 2。他们的每次 append 操作都需要拷贝整个原串,因此他们的性能将是 O(n2)的(译注:这个地方不是很理解,可能说的是包括在常量池中寻找字符串的时间)。使用他们再合并数十万个字符串时可能要花数分钟。从图中可以看书,与前面一个测试相比较,方法 3,4,6 在规模增大时每秒合并的字符串数目在减少。这个

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号