猿问
下载APP

如何在Python中将一个字符串附加到另一个字符串?

我想要一种有效的方法在Python中将一个字符串附加到另一个字符串。


var1 = "foo"

var2 = "bar"

var3 = var1 + var2

有没有什么好的内置方法可供使用?


智慧大石
浏览 92回答 3
3回答

侃侃无极

如果你只有一个字符串的引用,并且你将另一个字符串连接到结尾,CPython现在特殊情况,并尝试扩展字符串。最终结果是操作是摊销O(n)。例如s = ""for i in range(n):&nbsp; &nbsp; s+=str(i)曾经是O(n ^ 2),但现在是O(n)。从源代码(bytesobject.c):voidPyBytes_ConcatAndDel(register PyObject **pv, register PyObject *w){&nbsp; &nbsp; PyBytes_Concat(pv, w);&nbsp; &nbsp; Py_XDECREF(w);}/* The following function breaks the notion that strings are immutable:&nbsp; &nbsp;it changes the size of a string.&nbsp; We get away with this only if there&nbsp; &nbsp;is only one module referencing the object.&nbsp; You can also think of it&nbsp; &nbsp;as creating a new string object and destroying the old one, only&nbsp; &nbsp;more efficiently.&nbsp; In any case, don't use this if the string may&nbsp; &nbsp;already be known to some other part of the code...&nbsp; &nbsp;Note that if there's not enough memory to resize the string, the original&nbsp; &nbsp;string object at *pv is deallocated, *pv is set to NULL, an "out of&nbsp; &nbsp;memory" exception is set, and -1 is returned.&nbsp; Else (on success) 0 is&nbsp; &nbsp;returned, and the value in *pv may or may not be the same as on input.&nbsp; &nbsp;As always, an extra byte is allocated for a trailing \0 byte (newsize&nbsp; &nbsp;does *not* include that), and a trailing \0 byte is stored.*/int_PyBytes_Resize(PyObject **pv, Py_ssize_t newsize){&nbsp; &nbsp; register PyObject *v;&nbsp; &nbsp; register PyBytesObject *sv;&nbsp; &nbsp; v = *pv;&nbsp; &nbsp; if (!PyBytes_Check(v) || Py_REFCNT(v) != 1 || newsize < 0) {&nbsp; &nbsp; &nbsp; &nbsp; *pv = 0;&nbsp; &nbsp; &nbsp; &nbsp; Py_DECREF(v);&nbsp; &nbsp; &nbsp; &nbsp; PyErr_BadInternalCall();&nbsp; &nbsp; &nbsp; &nbsp; return -1;&nbsp; &nbsp; }&nbsp; &nbsp; /* XXX UNREF/NEWREF interface should be more symmetrical */&nbsp; &nbsp; _Py_DEC_REFTOTAL;&nbsp; &nbsp; _Py_ForgetReference(v);&nbsp; &nbsp; *pv = (PyObject *)&nbsp; &nbsp; &nbsp; &nbsp; PyObject_REALLOC((char *)v, PyBytesObject_SIZE + newsize);&nbsp; &nbsp; if (*pv == NULL) {&nbsp; &nbsp; &nbsp; &nbsp; PyObject_Del(v);&nbsp; &nbsp; &nbsp; &nbsp; PyErr_NoMemory();&nbsp; &nbsp; &nbsp; &nbsp; return -1;&nbsp; &nbsp; }&nbsp; &nbsp; _Py_NewReference(*pv);&nbsp; &nbsp; sv = (PyBytesObject *) *pv;&nbsp; &nbsp; Py_SIZE(sv) = newsize;&nbsp; &nbsp; sv->ob_sval[newsize] = '\0';&nbsp; &nbsp; sv->ob_shash = -1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* invalidate cached hash value */&nbsp; &nbsp; return 0;}通过经验验证很容易。$ python -m timeit -s“s =''”“for for in xrange(10):s + ='a'”1000000循环,最佳3:1.85每循环usec$ python -m timeit -s“s =''”“for for in xrange(100):s + ='a'”10000循环,最佳3:每循环使用16.8次$ python -m timeit -s“s =''”“for x in xrange(1000):s + ='a'”10000循环,最佳3:158每循环usec$ python -m timeit -s“s =''”“for for in xrange(10000):s + ='a'”1000个循环,最佳3:每循环1.71毫秒$ python -m timeit -s“s =''”“for x in xrange(100000):s + ='a'”10个循环,最佳3:每循环14.6毫秒$ python -m timeit -s“s =''”“for x in xrange(1000000):s + ='a'”10个循环,每个循环最好为3:173毫秒这一点很重要要注意的是这种优化是不是Python的规范的一部分。但是。据我所知,这只是在cPython实现中。例如,对于pypy或jython的相同经验测试可能会显示较旧的O(n ** 2)性能。$ pypy -m timeit -s“s =''”“for x in xrange(10):s + ='a'”10000循环,最佳3:90.8 usec每循环$ pypy -m timeit -s“s =''”“for for in xrange(100):s + ='a'”1000循环,最佳3:896 usec每循环$ pypy -m timeit -s“s =''”“for for in xrange(1000):s + ='a'”100个循环,最佳3:每循环9.03毫秒$ pypy -m timeit -s“s =''”“for for in xrange(10000):s + ='a'”10个循环,最佳3:每循环89.5毫秒到目前为止很好,但是,$ pypy -m timeit -s“s =''”“for x in xrange(100000):s + ='a'”10个循环,每个循环最佳3:12.8秒哎哟比二次更糟糕。因此pypy正在做一些适用于短字符串的东西,但对于较大的字符串表现不佳。

holdtom

不要过早优化。如果你没有理由相信有致的字符串连接的速度瓶颈,那么就坚持+和+=:s&nbsp; = 'foo's += 'bar's += 'baz'也就是说,如果你的目标是像Java的StringBuilder,那么规范的Python习惯是将项添加到列表中,然后用str.join它们将它们连接起来:l = []l.append('foo')l.append('bar')l.append('baz')s = ''.join(l)

慕慕0277861

别。也就是说,对于大多数情况,您最好一次性生成整个字符串,而不是附加到现有字符串。例如,不要这样做: obj1.name + ":" + str(obj1.count)相反:使用 "%s:%d" % (obj1.name, obj1.count)这将更容易阅读和更有效。
打开App,查看更多内容
随时随地看视频慕课网APP
我要回答