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

在Python中如何将一个字符串附加到另一个字符串?,python,string,append,Python,String,Append,我想要一种在Python中将一个字符串附加到另一个字符串的有效方法,而不是下面的方法 var1 = "foo" var2 = "bar" var3 = var1 + var2 有什么好的内置方法可以使用吗?如果需要执行许多附加操作来构建一个大字符串,可以使用或cStringIO。界面就像一个文件。ie:您可以编写来向其添加文本 如果只是附加两个字符串,那么只需使用+ str1 = "Hello" str2 = "World" newstr = " ".join((str1, str2)) 用

我想要一种在Python中将一个字符串附加到另一个字符串的有效方法,而不是下面的方法

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

有什么好的内置方法可以使用吗?

如果需要执行许多附加操作来构建一个大字符串,可以使用或cStringIO。界面就像一个文件。ie:您可以
编写
来向其添加文本

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

str1 = "Hello"
str2 = "World"
newstr = " ".join((str1, str2))
用一个空格作为分隔符连接str1和str2。您还可以执行
”。加入(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

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

从源代码(bytesobject.c):

void
PyBytes_ConcatAndDel(寄存器PyObject**pv,寄存器PyObject*w)
{
PyBytes_Concat(pv,w);
Py_XDECREF(w);
}
/*以下函数打破了字符串不可变的概念:
它更改字符串的大小。只有在有条件的情况下,我们才能逃脱惩罚
只有一个模块引用该对象。你也可以想想
创建新的字符串对象并销毁旧的字符串对象时
效率更高。在任何情况下,如果字符串可能
已经为代码的其他部分所知。。。
请注意,如果没有足够的内存来调整字符串的大小,则原始
*pv处的字符串对象被解除分配,*pv被设置为NULL,是一个“out of of”
设置“内存”异常,并返回-1。否则(成功时)0将被禁用
返回,*pv中的值可能与输入时的值相同,也可能不同。
与往常一样,会为尾随的\0字节(newsize)分配一个额外的字节
*不*包括),并存储一个尾随的\0字节。
*/
int
_PyBytes\u Resize(PyObject**pv,Py\u ssize\u t newsize)
{
寄存器PyObject*v;
寄存器PyBytesObject*sv;
v=*pv;
如果(!PyBytes|u Check(v)| Py|u REFCNT(v)!=1 | | newsize<0){
*pv=0;
Py_DECREF(v);
PyErr_BadInternalCall();
返回-1;
}
/*XXX UNREF/NEWREF接口应更加对称*/
_Py_DEC_ref total;
_Py_遗忘参照(v);
*pv=(PyObject*)
PyObject_REALLOC((char*)v,PyBytesObject_大小+新闻大小);
如果(*pv==NULL){
PyObject_Del(v);
PyErr_nomery();
返回-1;
}
_Py_新参考(*pv);
sv=(PyBytesObject*)*pv;
Py_尺寸(sv)=新尺寸;
sv->ob_sval[newsize]='\0';
sv->ob_shash=-1;/*使缓存的哈希值无效*/
返回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-m timeit-s“s=”,表示xrange(10)中的i:s+='a” 1000000个循环,最好3个:每个循环1.85 usec $python-m timeit-s“s=”,表示xrange(100)中的i:s+='a” 10000个循环,最好3个:每个循环16.8 usec $python-m timeit-s“s=”,表示x范围内的i(1000):s+='a” 10000个循环,最好3个:每个循环158个usec $python-m timeit-s“s=”,表示x范围内的i(10000):s+='a” 1000个循环,最佳3个:每个循环1.71毫秒 $python-m timeit-s“s=”,用于x范围内的i(100000):s+='a” 10个循环,最好3个:每个循环14.6毫秒 $python-m timeit-s“s=”,用于x范围内的i(1000000):s+='a” 10个循环,最好3个:每个循环173毫秒 但是,重要的是要注意,这种优化不是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=”,用于x范围(10)中的i:s+='a” 10000个循环,最好3个:每个循环90.8 usec $pypy-m timeit-s“s=”,用于x范围(100)中的i:s+='a” 1000个循环,最好3个:每个循环896 usec $pypy-m timeit-s“s=”,用于x范围内的i(1000):s+='a” 100个循环,最好为3:9.03毫秒/循环 $pypy-m timeit-s“s=”,用于x范围内的i(10000):s+='a” 10个循环,最好为3个:每个循环89.5毫秒 到目前为止还不错,但是

$ pypy -m timeit -s"s=''" "for i in xrange(100000):s+='a'" 10 loops, best of 3: 12.8 sec per loop $pypy-m timeit-s“s=”,用于x范围内的i(100000):s+='a” 10圈,最好3圈:每圈12.8秒
哎哟,比二次型还要糟糕。因此,pypy在处理短字符串时效果很好,但在处理较大字符串时效果不佳。

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


列表 Python 2.7

1个循环,3个循环中最好:7.34s个循环

Python 3.4

1个循环,3个循环中最好:7.99s个循环

Python 3.5

1个循环,3个循环中最好:8.48s个循环

Python 3.6

1个循环,3个循环中最好:9.93s个循环


一串 Python 2.7

1个循环,3个循环中最好:7.41 $ pypy -m timeit -s"s=''" "for i in xrange(100000):s+='a'" 10 loops, best of 3: 12.8 sec per loop
%%timeit
x = []
for i in range(100000000):  # xrange on Python 2.7
    x.append('a')
x = ''.join(x)
%%timeit
x = ''
for i in range(100000000):  # xrange on Python 2.7
    x += 'a'
a='foo'
b='baaz'

a.__add__(b)

out: 'foobaaz'
str1 = "Hello"
str2 = " World"
str3 = str.__add__(str2)
print(str3)
Hello World
var1 = "foo"
var2 = "bar"
var3 = f"{var1}{var2}"
print(var3)                       # prints foobar
print(f"1 + 1 == {1 + 1}")        # prints 1 + 1 == 2