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

如何有效地将一个字符串附加到另一个字符串?是否有更快的替代方案:

var1 = "foo"
var2 = "bar"
var3 = var1 + var2

要处理列表中的多个字符串,请参阅如何将列表中的项连接(连接)为单个字符串

2284222 次浏览

如果你需要做很多追加操作来构建一个大字符串,你可以使用StringIO或cStringIO。界面就像一个文件。即:你write向它追加文本。

如果您只是附加两个字符串,那么只需使用+

str1 = "Hello"
str2 = "World"
newstr = " ".join((str1, str2))

用空格作为分隔符连接str1和str2。你也可以做"".join(str1, str2, ...)str.join()接受一个可迭代的,所以你必须把字符串放在列表或元组中。

这几乎和内置方法一样有效。

不要过早地优化。如果您没有理由相信字符串连接会导致速度瓶颈,那么请坚持使用++=

s  = 'foo'
s += 'bar'
s += 'baz'

也就是说,如果你的目标是像Java的StringBuilder这样的东西,规范的Python习语是将项目添加到列表中,然后使用str.join在最后将它们连接起来:

l = []
l.append('foo')
l.append('bar')
l.append('baz')


s = ''.join(l)

不要。

也就是说,在大多数情况下,您最好一次生成整个字符串,而不是附加到现有字符串。

例如,不要这样做:obj1.name + ":" + str(obj1.count)

使用"%s:%d" % (obj1.name, obj1.count)

这将更容易阅读和更有效。

这真的取决于你的应用程序。如果你循环浏览数百个单词并想将它们全部附加到列表中,.join()更好。但是如果你要组合一个长句,最好使用+=

如果您只有一个对字符串的引用,并且将另一个字符串连接到末尾,CPython现在对此进行特殊处理并尝试在适当的位置扩展字符串。

最终结果是该操作被摊销为O(n)。

e. g.

s = ""
for i in range(n):
s+=str(i)

以前是O(n^2),现在是O(n)。

从源(bytesObject. c):

void
PyBytes_ConcatAndDel(register PyObject **pv, register PyObject *w)
{
PyBytes_Concat(pv, w);
Py_XDECREF(w);
}




/* The following function breaks the notion that strings are immutable:
it changes the size of a string.  We get away with this only if there
is only one module referencing the object.  You can also think of it
as creating a new string object and destroying the old one, only
more efficiently.  In any case, don't use this if the string may
already be known to some other part of the code...
Note that if there's not enough memory to resize the string, the original
string object at *pv is deallocated, *pv is set to NULL, an "out of
memory" exception is set, and -1 is returned.  Else (on success) 0 is
returned, and the value in *pv may or may not be the same as on input.
As always, an extra byte is allocated for a trailing \0 byte (newsize
does *not* include that), and a trailing \0 byte is stored.
*/


int
_PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
{
register PyObject *v;
register PyBytesObject *sv;
v = *pv;
if (!PyBytes_Check(v) || Py_REFCNT(v) != 1 || newsize < 0) {
*pv = 0;
Py_DECREF(v);
PyErr_BadInternalCall();
return -1;
}
/* XXX UNREF/NEWREF interface should be more symmetrical */
_Py_DEC_REFTOTAL;
_Py_ForgetReference(v);
*pv = (PyObject *)
PyObject_REALLOC((char *)v, PyBytesObject_SIZE + newsize);
if (*pv == NULL) {
PyObject_Del(v);
PyErr_NoMemory();
return -1;
}
_Py_NewReference(*pv);
sv = (PyBytesObject *) *pv;
Py_SIZE(sv) = newsize;
sv->ob_sval[newsize] = '\0';
sv->ob_shash = -1;          /* invalidate cached hash value */
return 0;
}

凭经验验证很容易。

$ python -m timeit -s"s=''" "for i in xrange(10):s+='a'"
1000000 loops, best of 3: 1.85 usec per loop
$ python -m timeit -s"s=''" "for i in xrange(100):s+='a'"
10000 loops, best of 3: 16.8 usec per loop
$ python -m timeit -s"s=''" "for i in xrange(1000):s+='a'"
10000 loops, best of 3: 158 usec per loop
$ python -m timeit -s"s=''" "for i in xrange(10000):s+='a'"
1000 loops, best of 3: 1.71 msec per loop
$ python -m timeit -s"s=''" "for i in xrange(100000):s+='a'"
10 loops, best of 3: 14.6 msec per loop
$ python -m timeit -s"s=''" "for i in xrange(1000000):s+='a'"
10 loops, best of 3: 173 msec per loop

这很重要但是要注意,这种优化不是Python规范的一部分。据我所知,它只在cPython实现中。例如,对pypy或jython的相同经验测试可能会显示较旧的O(n**2)性能。

$ pypy -m timeit -s"s=''" "for i in xrange(10):s+='a'"
10000 loops, best of 3: 90.8 usec per loop
$ pypy -m timeit -s"s=''" "for i in xrange(100):s+='a'"
1000 loops, best of 3: 896 usec per loop
$ pypy -m timeit -s"s=''" "for i in xrange(1000):s+='a'"
100 loops, best of 3: 9.03 msec per loop
$ pypy -m timeit -s"s=''" "for i in xrange(10000):s+='a'"
10 loops, best of 3: 89.5 msec per loop

到目前为止还不错但是…

$ pypy -m timeit -s"s=''" "for i in xrange(100000):s+='a'"
10 loops, best of 3: 12.8 sec per loop

哎呀,比二次还要糟糕。所以pypy在短字符串上表现得很好,但在大字符串上表现不佳。

基本上没有区别。唯一一致的趋势是Python似乎在每个版本都变得越来越慢…:(


列表

%%timeit
x = []
for i in range(100000000):  # xrange on Python 2.7
x.append('a')
x = ''.join(x)

python2.7

1循环,最好的3:7.34 s每个循环

python3.4

1循环,最好的3:7.99 s每个循环

python3.5

1循环,最好的3:8.48 s每个循环

python3.6

1循环,最好的3:9.93 s每个循环


String

%%timeit
x = ''
for i in range(100000000):  # xrange on Python 2.7
x += 'a'

python2.7

1循环,最好的3:7.41秒每个循环

python3.4

1循环,最好的3:9.08 s每个循环

python3.5

1循环,最好的3:8.82 s每个循环

python3.6

1循环,最好的3:9.24 s每个循环

a='foo'
b='baaz'


a.__add__(b)


out: 'foobaaz'

使用添加函数追加字符串:

str1 = "Hello"
str2 = " World"
str3 = str1.__add__(str2)
print(str3)

输出:

Hello World

Python 3.6给了我们f字串,这是一种乐趣:

var1 = "foo"
var2 = "bar"
var3 = f"{var1}{var2}"
print(var3)                       # prints foobar

你可以在花括号里做任何事情

print(f"1 + 1 == {1 + 1}")        # prints 1 + 1 == 2

另一种选择是使用. formas如下:

print("{}{}".format(var1, var2))

取决于您要做什么。如果您将变量格式化为要打印的字符串,例如,您希望输出为:

Hello, Bob

鉴于Bob这个名字,你会希望我们%s. print("Hello, %s" % my_variable) 它高效,适用于所有数据类型(因此您不必像使用"a" + str(5)那样执行str(my_variable))。