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

本文讨论了在Python中如何有效地拼接字符串,包括不同Python版本的性能对比,推荐使用`+`操作符或`join()`方法。还提到了StringIO和cStringIO在大量拼接操作时的作用,以及Python的优化策略,如CPython对字符串连接的特殊处理。最后介绍了Python 3.6引入的f-string作为简洁高效的字符串格式化方式。
摘要由CSDN通过智能技术生成

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

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

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


#1楼

基本上没什么区别。 唯一一致的趋势是Python似乎每个版本都变慢...... :(


名单

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

Python 2.7

1个循环,最佳3:每循环7.34

Python 3.4

1个循环,每个循环最好为3: 7.99

Python 3.5

1循环,最佳3:每循环8.48

Python 3.6

1个循环,每个循环最好为3: 9.93


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

Python 2.7

1个循环,最佳3:每循环7.41秒

Python 3.4

1个循环,最佳3:每循环9.08

Python 3.5

1个循环,最佳3:每循环8.82

Python 3.6

1个循环,最佳3:每循环9.24


#2楼

a='foo'
b='baaz'

a.__add__(b)

out: 'foobaaz'

#3楼

如果需要执行许多追加操作来构建大型字符串,则可以使用StringIO或cStringIO。 界面就像一个文件。 即:你write以附加文本。

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


#4楼

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

这将str1和str2与空格连接为分隔符。 你也可以做"".join(str1, str2, ...)str.join()采用可迭代的方式,因此您必须将字符串放在列表或元组中。

这与内置方法一样高效。


#5楼

不要过早优化。 如果您没有理由相信字符串连接引起的速度瓶颈,那么只需坚持使用++=

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

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

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

s = ''.join(l)

#6楼

别。

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

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

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

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


#7楼

这真的取决于你的应用程序。 如果你循环遍历数百个单词并希望将它们全部附加到列表中,则.join()更好。 但如果你把一个长句放在一起,你最好用+=


#8楼

如果你只有一个字符串的引用,并且你将另一个字符串连接到结尾,CPython现在特殊情况,并尝试扩展字符串。

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

例如

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正在做一些适用于短字符串的东西,但对于较大的字符串表现不佳。


#9楼

__add__函数追加字符串

str = "Hello"
str2 = " World"
st = str.__add__(str2)
print(st)

产量

Hello World

#10楼

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值