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

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

介绍

在Python编程语言中,构造一些较长的字符串事常常会产生一些运行很慢的代码。本文我将研究不同字符串合并方法的计算性能。

在Python中,字符串(string)对象是不可变的(每次关联一个新的字符串变量都会在内存中创建一个新的对象)(译注:类同于Java,.NET等现代语言,他们都会在其VM中保留一个字符串池,里面保存所有产生的目标字符串值或临时字符串值)。这方面它与perl、VB等语言中的字符串变量可以任意修改有所不同。如果使用一些比较显而易见的方法(比如:每次都是在新产生的字符串末尾添加一个新短字符串片段)从一些短字符串片段构造长字符串在Python中可能会不是很有效率。每次你的在字符串末尾添加内容,Python解释器都会创建一个新的对象并且复制新产生的对象和原来的对象到解释器中(译注:应该是复制到Python解释器的字符串常量池中)。随着处理的字符串的增多,这样的处理过程将会越来越慢。

其他一些其他的方法呢?他们是否有效并且与原始方法相比它们性能方面如何?我决定试试一些其他的构造长字符串的方法,并看看它们在效率上都有啥不同。 为了比较,我需要一个测试程序来调用大量的字符串片段构造长字符串。它不应该有太多的额外计算,好让我们测试的性能仅仅依赖于字符串操作的性能。 我的测试用例是合并一些从0到某个大整数的数字。这样我们也可以很容易的改变需要产生字符串的大小(译注:改变那个大整数)。比如前20个整数产生如下的字符串:

[***********][1**********]19

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

下面是我测试的一些方法,每小段Python代码都返回相同的字符串。 方法一:朴素的添加(Method 1: Naive appending)

def method1():

out_str = ''

fornum in xrange(loop_count):

out_str += `num`

returnout_str

对于我来说,这是解决该问题的最显而易见的方法。使用字符串连接操作(+=)添加每个字符串片段到字符串中。loop_count告诉我们要添加的字符串片段数。第四行中的数字num两边的重音符(``)会把整数转换为相对于的字符串。你可以使用str()方法完成一样的功能,但是,比较起来它可能稍慢些,因此我所有的方法中都是使用重音符(``)。如我说言,尽管很浅显,但是这个方法根本不是很有效(译注:maybe应该加个”率”子)。你可以再下面的测试中看到它每秒仅仅能合并3770个字符串片段。如果你需要合并很多的字符串片段,那么这可能不是很好的解决方法。

方法二:MutableString 类(Method 2: MutableString class) def method2():

fromUserString import MutableString

out_str = MutableString()

fornum in xrange(loop_count):

out_str += `num`

returnout_str

Python类库中包括一个MutableString类。根据其文档描述它主要用于教学目的(译注:

UserString.py的源代码我发现字符串在MutableString中的存储就是string,MutableString甚至都没重写__add__方法。所以使用该类对象合并字符串不会比一般的不可变字符串更快,实际上由于解释MutableString方法需要一些额外的开销会使得该方法更慢。

方法三:字符数组(Method 3: Character arrrays)

def method3():

from array import array

char_array = array('c')

fornum in xrange(loop_count):

char_array.fromstring(`num`)

returnchar_array.tostring()

我几乎都没有尝试这种方法,但是邮件列表中有人提到了,所以我决定试试。该方法的思想就是用字符数组存储字符串。Python中的数组是可变的,所以它可以被原地改变(译注:也就是在该对象的那块内存上进行改变,而不需要通过复制到其他的空间上实现)而不需要拷贝现存的数组内容。这里我们对改变现存的数

组元素没有兴趣。我们只是在数组末尾添加一些新的数组元素。fromstring()方法一个字符一个字符的添加字符串字符到字符数组对象中。

方法四:构造一个字符串列表,然后join它(Method 4: Build a list of strings, then join it)

def method4():

str_list = []

fornum in xrange(loop_count):

str_list.append(`num`)

return ''.join(str_list)

这是一种通常被推荐的方法,因为它的字符串合并方法很Python。首先构造一个包含所有需要合并的字符串列表,然后使用一个字符串的join操作构造包含所有列表元素的字符串。

这人有点好玩,看看python习语的最后一行-我们在确定的空字符串上调用join方法。不是所有的语言都会让你在一个字面上的字符串调用方法(译注:这里的意识是’’是空字符串)。如果你觉得这儿有点不爽,你可以写成如下形式: string.join(str_list, '')。

方法五:写到一个伪文件中去(Method 5: Write to a pseudo file) def method5():

fromcStringIO import StringIO

file_str = StringIO()

fornum in xrange(loop_count):

file_str.write(`num`)

returnfile_str.getvalue()

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

有意思的是,同python类似,在java中字符串也是不可变的对象。Java中有个类叫StringBuffer,它比python中的StringIO和数组方法都更加强大,因为它不仅支持添加字符串还支持插入和删除子字符串操作。

方法六:列表推导 (Method 6: List comprehensions)

def method6():

return ''.join([`num` for num in xrange(loop_count)])

方法的代码是最短的。并且令人惊喜的是他也是最快的。它及其紧凑并且也非常好理解。使用列表推导创建一个列表并使用join方法合并它们。还如比这个简单的吗?实际上这是方法4的简略版,当然,它也需要消耗差不多的空间。它更快是因为不需要在循环的每次都调用list.append()方法。

测试结果

我想要查看合并字符串时所花费的时间和计算时Python解释器的内存使用情

况。尽管内存很便宜(译注:这里应该是内存开销不是非常大的意思),但是依然有很多原因使其成为一个重要的因素。首先,Python程序常常会运行在资源受限的系统上。例如,在一个共享虚拟主机的环境下,机器可能对每个进程设置了一定大小的内存使用。系统内核往往会杀死内存分配超过一定额度的进程。这种情况对于一些CGI脚本(译注: Computer Graphics Interface),长时运行的服务器程序来说将是不好的现象。所以在这种情况下,保存内存使用不超过预期是很重要的。另一个原因是当我们处理大量的字符串的时候,解释器的内存分配将会变得非常大可能会导致虚拟内存的访问(译注:paging是操作系统中的一个概念,表示对硬盘页面的访问)。这种情况下的性能将会直线下降。如果你发现了时间上最快的算法当然无所谓了---如果它使用了过多的内存将会允许得和狗(译注:应该是像蜗牛吧,J)一样慢。如果用的算法使用更少的内存,那么就会介绍paging的机会,我们也将会有更多的可预测性能。

我使用自己的Python过程分别测试每种方法。

我在一台按照了FreeBSD 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(n^2)的(译注:这个地方不是很理解,可能说的是包括在常量池中寻找字符串的时间)。使用他们再合并数十万个字符串时可能要花数分钟。

从图中可以看书,与前面一个测试相比较,方法3,4,6在规模增大时每秒合并的字符串数目在减少。这个不奇怪(由于整数值的增大,相对于的字符串表示也在增大,大概前一个测试中的5个相当于该测试的4个吧)。在第一个测试中,方法3比前两个方法块了近10倍,但是它性能在更大规模数据上的测试并没有相应的提升。其实它比之前还慢了60%,但相较于其他方法它使用了更少的空间。很明显,Python在有效的存储数组和临时字符串的垃圾回收上做了一些工作。

方法4在性能上比朴素的添加提高了很多,在两万个数据的测试中提高了近20倍在五十万的数据上也有很好的提高。方法6始终是最好的,但是方法5也有很好的性能,并且直追方法6。我们猜测,当测试更大规模数据的时候,方法5会超过方法6。

我们也要注意到空间开销的大小。方法6的解释器使用了22,844kB的内存,8倍于其实际的大小,反而方法3和方法5仅仅使用了其一般的内存。 总结

我在实际编程中常常使用方法7,它很快并且也很好理解。它仅需要你写一个返回需要添加字符串的表达式。有的时候这可能不是很方便,比如:有多个不同的字符串快需要用于合并时,这种情况下,你可能需要使用方法4和方法5。 方法4在可行上更好。你可以使用在添加的字符串列表上切片,或者插入,删除和修改操作。它在添加操作上的性能也是很好的。

方法五在效率上更好。它使用更少的内存(远少于方法4和6),并且在处理大量数据(大概多于700,000时)时比列表推导的更快。如果你需要添加非常多的字符串,cStringIO是一个很好的方向。

测试技术

计算每个方法的执行时间相对来说还比较容易。我使用Python类库中的timing模块计算花费的时间。我没有试图去该除了运行于该机上的其他程序,单独计算

所运行的Python程序的CPU时间开销,但是除了Python程序,机器是空闲的,所以我不认为此处计算出的时间与CPU的运行时间有什么不一样的。 计算内存开销就有点困难了,因为Python本身没有提供方法用于监控其所分配对象的空间占用大小(译注:这点上JVM做的很好,它的tools.jar包里面有很多性能监控的工具),所以我使用了UNIX的’PS’命令去监控它。因为占用空间会随着程序的运行而改变,而我想计算其最大的分配空间。为了得到结果,我在计算完成的时候运行’ps’命令。ps_stat()的调用插在合并方法return语句前,因此可以在垃圾回收启动前计算其程序占用空间大小。我稍稍的改变了一点你在上面看到的代码---ps_stat()运行的计算结果用一个字符串变量存储。我执行的ps_stat()方法分离ps命令返回的各个域项并选择内存使用大小项所对应的值。这里是使用15,可能不同版本的ps程序需要不同的值。

我使用的全部代码在这里。

fromcStringIO import StringIO

import timing, commands, os

from sys import argv

# .....

# method definitions go here

# .....

defps_stat():

globalprocess_size

ps = commands.getoutput('ps -up ' + `pid`)

process_size = ps.split()[15]

defcall_method(num):

globalprocess_size

timing.start()

z = eval('method' + str(num))()

timing.finish()

print

print

print

print

print

loop_count = 500000

pid = os.getpid()

call_method(argv[1])

备注1:翻译自文章Efficient String Concatenation in Python

备注2:在文章题目的翻译上,我纠结于“Python中有效的字符串拼接方法”和“Python中有效的字符串合并方法”很久,最后还是觉得第一句中太口语化了,并且可能也仅仅是我自己喜欢拼接这个词,所以还是选择了“合并”。

备注3:其实这些方法中我用到较多的还是方法3和方法6,其他的还真不太了解。另外,文章中的那两个图,我没有通过自己的实验数据结果来画,主要还是我不太会画。Python还不是很熟悉,那些绘图模块更不熟悉了,这个还有加以学习。

备注4:文章后面还有两段内容,不过与本文主题没有什么关系,就没有翻译了。这篇文章也算是正了八经的翻译的一篇吧。以前翻译的都是只有几段文字的短文。曾试图翻译过wikipedia的article,但最终都没成文。读书的时候,我其实是很不喜欢,也不是非常欣赏那种通过翻译文章来理解文章的做法,但是现在我发现我错了,理解固然主要,但如果能翻译那就是更高层次的理解;很多时候,我觉得对原文理解了,但是没法用自己的母语去描述它,这说明我还是没有很好的理解。就像对某个概念的理解,我做不到能书写或者讲授,那也说明我没有理解透彻。

最好,这篇文章也翻译的匆忙,肯定不如人意的地方大大多于有点价值的地方。还忘大家不要吝啬批评指正。

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

介绍

在Python编程语言中,构造一些较长的字符串事常常会产生一些运行很慢的代码。本文我将研究不同字符串合并方法的计算性能。

在Python中,字符串(string)对象是不可变的(每次关联一个新的字符串变量都会在内存中创建一个新的对象)(译注:类同于Java,.NET等现代语言,他们都会在其VM中保留一个字符串池,里面保存所有产生的目标字符串值或临时字符串值)。这方面它与perl、VB等语言中的字符串变量可以任意修改有所不同。如果使用一些比较显而易见的方法(比如:每次都是在新产生的字符串末尾添加一个新短字符串片段)从一些短字符串片段构造长字符串在Python中可能会不是很有效率。每次你的在字符串末尾添加内容,Python解释器都会创建一个新的对象并且复制新产生的对象和原来的对象到解释器中(译注:应该是复制到Python解释器的字符串常量池中)。随着处理的字符串的增多,这样的处理过程将会越来越慢。

其他一些其他的方法呢?他们是否有效并且与原始方法相比它们性能方面如何?我决定试试一些其他的构造长字符串的方法,并看看它们在效率上都有啥不同。 为了比较,我需要一个测试程序来调用大量的字符串片段构造长字符串。它不应该有太多的额外计算,好让我们测试的性能仅仅依赖于字符串操作的性能。 我的测试用例是合并一些从0到某个大整数的数字。这样我们也可以很容易的改变需要产生字符串的大小(译注:改变那个大整数)。比如前20个整数产生如下的字符串:

[***********][1**********]19

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

下面是我测试的一些方法,每小段Python代码都返回相同的字符串。 方法一:朴素的添加(Method 1: Naive appending)

def method1():

out_str = ''

fornum in xrange(loop_count):

out_str += `num`

returnout_str

对于我来说,这是解决该问题的最显而易见的方法。使用字符串连接操作(+=)添加每个字符串片段到字符串中。loop_count告诉我们要添加的字符串片段数。第四行中的数字num两边的重音符(``)会把整数转换为相对于的字符串。你可以使用str()方法完成一样的功能,但是,比较起来它可能稍慢些,因此我所有的方法中都是使用重音符(``)。如我说言,尽管很浅显,但是这个方法根本不是很有效(译注:maybe应该加个”率”子)。你可以再下面的测试中看到它每秒仅仅能合并3770个字符串片段。如果你需要合并很多的字符串片段,那么这可能不是很好的解决方法。

方法二:MutableString 类(Method 2: MutableString class) def method2():

fromUserString import MutableString

out_str = MutableString()

fornum in xrange(loop_count):

out_str += `num`

returnout_str

Python类库中包括一个MutableString类。根据其文档描述它主要用于教学目的(译注:

UserString.py的源代码我发现字符串在MutableString中的存储就是string,MutableString甚至都没重写__add__方法。所以使用该类对象合并字符串不会比一般的不可变字符串更快,实际上由于解释MutableString方法需要一些额外的开销会使得该方法更慢。

方法三:字符数组(Method 3: Character arrrays)

def method3():

from array import array

char_array = array('c')

fornum in xrange(loop_count):

char_array.fromstring(`num`)

returnchar_array.tostring()

我几乎都没有尝试这种方法,但是邮件列表中有人提到了,所以我决定试试。该方法的思想就是用字符数组存储字符串。Python中的数组是可变的,所以它可以被原地改变(译注:也就是在该对象的那块内存上进行改变,而不需要通过复制到其他的空间上实现)而不需要拷贝现存的数组内容。这里我们对改变现存的数

组元素没有兴趣。我们只是在数组末尾添加一些新的数组元素。fromstring()方法一个字符一个字符的添加字符串字符到字符数组对象中。

方法四:构造一个字符串列表,然后join它(Method 4: Build a list of strings, then join it)

def method4():

str_list = []

fornum in xrange(loop_count):

str_list.append(`num`)

return ''.join(str_list)

这是一种通常被推荐的方法,因为它的字符串合并方法很Python。首先构造一个包含所有需要合并的字符串列表,然后使用一个字符串的join操作构造包含所有列表元素的字符串。

这人有点好玩,看看python习语的最后一行-我们在确定的空字符串上调用join方法。不是所有的语言都会让你在一个字面上的字符串调用方法(译注:这里的意识是’’是空字符串)。如果你觉得这儿有点不爽,你可以写成如下形式: string.join(str_list, '')。

方法五:写到一个伪文件中去(Method 5: Write to a pseudo file) def method5():

fromcStringIO import StringIO

file_str = StringIO()

fornum in xrange(loop_count):

file_str.write(`num`)

returnfile_str.getvalue()

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

有意思的是,同python类似,在java中字符串也是不可变的对象。Java中有个类叫StringBuffer,它比python中的StringIO和数组方法都更加强大,因为它不仅支持添加字符串还支持插入和删除子字符串操作。

方法六:列表推导 (Method 6: List comprehensions)

def method6():

return ''.join([`num` for num in xrange(loop_count)])

方法的代码是最短的。并且令人惊喜的是他也是最快的。它及其紧凑并且也非常好理解。使用列表推导创建一个列表并使用join方法合并它们。还如比这个简单的吗?实际上这是方法4的简略版,当然,它也需要消耗差不多的空间。它更快是因为不需要在循环的每次都调用list.append()方法。

测试结果

我想要查看合并字符串时所花费的时间和计算时Python解释器的内存使用情

况。尽管内存很便宜(译注:这里应该是内存开销不是非常大的意思),但是依然有很多原因使其成为一个重要的因素。首先,Python程序常常会运行在资源受限的系统上。例如,在一个共享虚拟主机的环境下,机器可能对每个进程设置了一定大小的内存使用。系统内核往往会杀死内存分配超过一定额度的进程。这种情况对于一些CGI脚本(译注: Computer Graphics Interface),长时运行的服务器程序来说将是不好的现象。所以在这种情况下,保存内存使用不超过预期是很重要的。另一个原因是当我们处理大量的字符串的时候,解释器的内存分配将会变得非常大可能会导致虚拟内存的访问(译注:paging是操作系统中的一个概念,表示对硬盘页面的访问)。这种情况下的性能将会直线下降。如果你发现了时间上最快的算法当然无所谓了---如果它使用了过多的内存将会允许得和狗(译注:应该是像蜗牛吧,J)一样慢。如果用的算法使用更少的内存,那么就会介绍paging的机会,我们也将会有更多的可预测性能。

我使用自己的Python过程分别测试每种方法。

我在一台按照了FreeBSD 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(n^2)的(译注:这个地方不是很理解,可能说的是包括在常量池中寻找字符串的时间)。使用他们再合并数十万个字符串时可能要花数分钟。

从图中可以看书,与前面一个测试相比较,方法3,4,6在规模增大时每秒合并的字符串数目在减少。这个不奇怪(由于整数值的增大,相对于的字符串表示也在增大,大概前一个测试中的5个相当于该测试的4个吧)。在第一个测试中,方法3比前两个方法块了近10倍,但是它性能在更大规模数据上的测试并没有相应的提升。其实它比之前还慢了60%,但相较于其他方法它使用了更少的空间。很明显,Python在有效的存储数组和临时字符串的垃圾回收上做了一些工作。

方法4在性能上比朴素的添加提高了很多,在两万个数据的测试中提高了近20倍在五十万的数据上也有很好的提高。方法6始终是最好的,但是方法5也有很好的性能,并且直追方法6。我们猜测,当测试更大规模数据的时候,方法5会超过方法6。

我们也要注意到空间开销的大小。方法6的解释器使用了22,844kB的内存,8倍于其实际的大小,反而方法3和方法5仅仅使用了其一般的内存。 总结

我在实际编程中常常使用方法7,它很快并且也很好理解。它仅需要你写一个返回需要添加字符串的表达式。有的时候这可能不是很方便,比如:有多个不同的字符串快需要用于合并时,这种情况下,你可能需要使用方法4和方法5。 方法4在可行上更好。你可以使用在添加的字符串列表上切片,或者插入,删除和修改操作。它在添加操作上的性能也是很好的。

方法五在效率上更好。它使用更少的内存(远少于方法4和6),并且在处理大量数据(大概多于700,000时)时比列表推导的更快。如果你需要添加非常多的字符串,cStringIO是一个很好的方向。

测试技术

计算每个方法的执行时间相对来说还比较容易。我使用Python类库中的timing模块计算花费的时间。我没有试图去该除了运行于该机上的其他程序,单独计算

所运行的Python程序的CPU时间开销,但是除了Python程序,机器是空闲的,所以我不认为此处计算出的时间与CPU的运行时间有什么不一样的。 计算内存开销就有点困难了,因为Python本身没有提供方法用于监控其所分配对象的空间占用大小(译注:这点上JVM做的很好,它的tools.jar包里面有很多性能监控的工具),所以我使用了UNIX的’PS’命令去监控它。因为占用空间会随着程序的运行而改变,而我想计算其最大的分配空间。为了得到结果,我在计算完成的时候运行’ps’命令。ps_stat()的调用插在合并方法return语句前,因此可以在垃圾回收启动前计算其程序占用空间大小。我稍稍的改变了一点你在上面看到的代码---ps_stat()运行的计算结果用一个字符串变量存储。我执行的ps_stat()方法分离ps命令返回的各个域项并选择内存使用大小项所对应的值。这里是使用15,可能不同版本的ps程序需要不同的值。

我使用的全部代码在这里。

fromcStringIO import StringIO

import timing, commands, os

from sys import argv

# .....

# method definitions go here

# .....

defps_stat():

globalprocess_size

ps = commands.getoutput('ps -up ' + `pid`)

process_size = ps.split()[15]

defcall_method(num):

globalprocess_size

timing.start()

z = eval('method' + str(num))()

timing.finish()

print

print

print

print

print

loop_count = 500000

pid = os.getpid()

call_method(argv[1])

备注1:翻译自文章Efficient String Concatenation in Python

备注2:在文章题目的翻译上,我纠结于“Python中有效的字符串拼接方法”和“Python中有效的字符串合并方法”很久,最后还是觉得第一句中太口语化了,并且可能也仅仅是我自己喜欢拼接这个词,所以还是选择了“合并”。

备注3:其实这些方法中我用到较多的还是方法3和方法6,其他的还真不太了解。另外,文章中的那两个图,我没有通过自己的实验数据结果来画,主要还是我不太会画。Python还不是很熟悉,那些绘图模块更不熟悉了,这个还有加以学习。

备注4:文章后面还有两段内容,不过与本文主题没有什么关系,就没有翻译了。这篇文章也算是正了八经的翻译的一篇吧。以前翻译的都是只有几段文字的短文。曾试图翻译过wikipedia的article,但最终都没成文。读书的时候,我其实是很不喜欢,也不是非常欣赏那种通过翻译文章来理解文章的做法,但是现在我发现我错了,理解固然主要,但如果能翻译那就是更高层次的理解;很多时候,我觉得对原文理解了,但是没法用自己的母语去描述它,这说明我还是没有很好的理解。就像对某个概念的理解,我做不到能书写或者讲授,那也说明我没有理解透彻。

最好,这篇文章也翻译的匆忙,肯定不如人意的地方大大多于有点价值的地方。还忘大家不要吝啬批评指正。


相关内容

  • 大一上半学期学习总结
  • 大一上半学期学习总结 Oj刷题类型归纳 语言入门类: A+B Problem 三个数从小到大排序 奇偶数分离 ASCII码排序 Fibonacci数 5个数求最值 韩信点兵 算菜价 水仙花数 公约数和公倍数 三个数从小到大排序 6174问题 鸡兔同笼 另一种阶乘问题 Financial Manage ...

  • python模块介绍- argparse:命令行选项及参数解析
  • #承接软件自动化实施与培训等gtalk:ouyangchongwu#gmail.com qq 37391319 博客: http://blog.csdn.net/oychw #版权所有,转载刊登请来函联系 #自动化测试和python群组: http://groups.google.com/group ...

  • 如何写一份好的简历
  • 程序员如何写一份好的简历 昨天写了些应届毕业生简历的常见问题,很多人觉得我太苛刻,觉得对应届生要求有点高:有的觉得看了后还是不会写.那么今天我们就来看看怎么才能做 好.需要声明的是我帮不了太多人,只有那些对计算机科学真的有点兴趣的人可能觉得我说的有点用.这里写的东西仅仅是我们的观点,不代表别的公司也 ...

  • 回归.分类与聚类:三大方向剖解机器学习算法的优缺点(附Python和R实现)
  • 选自EliteDataScience 机器之心编译 参与:蒋思源.晏奇 在本教程中,作者对现代机器学习算法进行一次简要的实战梳理.虽然类似的总结有很多,但是它们都没有真正解释清楚每个算法在实践中的好坏,而这正是本篇梳理希望完成的.因此本文力图基于实践中的经验,讨论每个算法的优缺点.而机器之心也在文末 ...

  • 软件需求分析报告
  • 软件需求分析报告 1. 引言 本文档是为自动作曲系统所编写的软件需求分析报告.文档主要包括文档说明,软件的综合描述等几个方面,用于指导软件的开发以及对软件相关功能的说明 1.1 编写目的 由于国内版权意识不断加强,使音乐的使用价格既版权价格不断升高,而自动作曲系统所生成的歌曲具有无版权,形式多样等特 ...

  • 计算机相关专业实习报告
  • 专业实习报告871279 朱育民一.工作内容这学期跟李锡捷老师实习,参加的工作项目是信息安全组,因为平时较其它三位组员多接触unix-like的环境,因此成为本组组长并协助联络事情.我们期初一开始便有正式的case接手,是一个韩国的骇客教育机构hackerslab委托翻译他们的一份骇客教材.对于这方 ...

  • GIS数据工程师成长之路
  • GIS 数据工程师成长路 1. 题记 Esri中国社区已经走过了6个年头,自己进入这个大家庭也整整4年有余:社区为大家提供一个相互学习.交流的平台,通过社区也结识了很多GIS 行业达人.技术牛人,为自己的成长路增添许多捷径.在六周年之际,书此一文简单阐述"GIS数据工程师"成长之 ...

  • 出色通信工程(电子)汪是这样炼成的
  • 我们当中,很多通信专业的同学,在读书的时候不知道该做啥,在毕业了以后也不知道该干嘛,职业规划和能力提高都不知道怎么下手,我们来看一下李宇同学是怎么处理这些问题的. 通信工程狗在大学要学啥 先简单介绍一下,作者本科时候985学校的通信工程,到现在工作满4年,在武汉一私企,14K月薪. 这水平在很多北上 ...

  • 建设BT服务器方法
  • by james in实用软件 at 2005年10月2日03:12星期日 帶寬小的人可以干大事!丢掉ftp server,建BT Server. 例如对于电信的512kbits/s的ADSL(也就是64kByte/s),把电脑变成BT Server,效果就像传销一样,例如你把naruto31.rm ...