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

2025-01-07 08:44:00
admin
原创
96
摘要:问题描述:如何有效地将一个字符串附加到另一个字符串?有没有更快的替代方案:var1 = "foo" var2 = "bar" var3 = var1 + var2 要处理列表中的多个字符串,请参阅如何将列表中的项目连接(连接)为单个字符串。如果某些输入不是字符串,请参阅...

问题描述:

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

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

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

如果某些输入不是字符串,请参阅如何将变量的值放入字符串中(将其插入到字符串中)?但结果仍然应该是字符串。


解决方案 1:

如果您只有一个对字符串的引用,并且将另一个字符串连接到末尾,则 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  byte (newsize
   does *not* include that), and a trailing  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] = '';
    sv->ob_shash = -1;          /* invalidate cached hash value */
    return 0;
}

通过经验来验证是相当容易的。

$ python -m timeit -s“s =''” “对于 xrange(10) 中的 i:s + ='a'”
1000000 次循环,3 次中最佳:每次循环 1.85 微秒
$ python -m timeit -s“s =''” “对于 xrange(100) 中的 i:s + ='a'”
10000 次循环,3 次中最佳:每次循环 16.8 微秒
$ python -m timeit -s“s =''”“对于i在xrange(1000)中:s + ='a'”
10000 次循环,3 次中最佳:每次循环 158 微秒
$ python -m timeit -s“s =''” “对于 xrange(10000) 中的 i:s + ='a'”
1000 次循环,3 次中最佳:每次循环 1.71 毫秒
$ python -m timeit -s“s =''” “对于 xrange(100000) 中的 i:s + ='a'”
10 次循环,3 次最佳:每次循环 14.6 毫秒
$ python -m timeit -s“s =''” “对于 xrange 中的 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 次循环,3 次中最佳:每次循环 90.8 微秒
$ pypy -m timeit -s“s=''” “for i in xrange(100):s+='a'”
1000 次循环,3 次中最佳:每次循环 896 微秒
$ pypy -m timeit -s“s=''” “for i in xrange(1000):s+='a'”
100 次循环,3 次最佳:每次循环 9.03 毫秒
$ pypy -m timeit -s“s=''” “for i in xrange(10000):s+='a'”
10 次循环,3 次最佳:每次循环 89.5 毫秒

到目前为止一切都很好,但是,

$ pypy -m timeit -s“s=''” “for i in xrange(100000):s+='a'”
10 圈,3 圈最佳:每圈 12.8 秒

哎呀,甚至比二次方还糟糕。所以 pypy 正在做一些对短字符串很有效,但对较长的字符串表现不佳的事情。

解决方案 2:

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

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

也就是说,如果您想要类似 Java 的 StringBuilder 之类的东西,那么规范的 Python 习惯用法是将项目添加到列表中,然后str.join在最后使用它们全部连接起来:

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

s = ''.join(l)

解决方案 3:

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

这将 str1 和 str2 连接起来,并以空格作为分隔符。您也可以这样做"".join(str1, str2, ...)str.join()采用可迭代对象,因此您必须将字符串放在列表或元组中。

这对于内置方法来说几乎是最高效的。

解决方案 4:

不。

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

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

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

这将更易于阅读并且更加高效。

解决方案 5:

Python 3.6 为我们提供了令人欣喜的f-strings :

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

你可以在花括号内执行大多数操作

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

解决方案 6:

如果要附加两个字符串,则只需使用+

如果需要执行许多附加操作来构建大型字符串,则可以使用StringIO。该接口就像一个文件:您write可以将文本附加到其中,然后使用它getvalue()来获取组合的字符串。

解决方案 7:

这确实取决于你的应用程序。如果你要循环数百个单词并希望将它们全部添加到列表中,.join()则更好。但如果你要组合一个长句子,最好使用+=

解决方案 8:

基本上没有区别。唯一一致的趋势是 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

解决方案 9:

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

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

输出:

Hello World

解决方案 10:

a='foo'
b='baaz'

a.__add__(b)

out: 'foobaaz'

解决方案 11:

另一个选择是使用 .format ,如下所示:

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

解决方案 12:

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

Hello, Bob

鉴于名字 Bob,您会希望我们%s. print("Hello, %s" % my_variable)
它很高效,并且适用于所有数据类型(因此您不必str(my_variable)像对待那样做"a" + str(5))。

解决方案 13:

您可以使用它来连接字符串:f“{var1} {var2}”

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用