Как добавить одну строку в другую в Python?

Мне нужен эффективный способ добавления одной строки к другой в Python, кроме следующего.

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 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

ouch даже хуже, чем квадратичный. Таким образом, pypy делает что-то, что хорошо работает с короткими строками, но плохо работает для больших строк.

Ответ 2

Не следует преждевременно оптимизировать. Если у вас нет причин полагать, что есть узкое место в скорости, вызванное конкатенациями строк, тогда просто придерживайтесь + и +=:

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

Не.

То есть, в большинстве случаев вам лучше создать целую строку за один раз, а затем добавить к существующей строке.

Например, не делайте: obj1.name + ":" + str(obj1.count)

Вместо этого используйте "%s:%d" % (obj1.name, obj1.count)

Это будет легче читать и более эффективно.

Ответ 4

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

Это соединяет str1 и str2 с пробелом в качестве разделителей. Вы также можете сделать "".join(str1, str2, ...). str.join() принимает итерацию, поэтому вам нужно будет поместить строки в список или кортеж.

Это примерно так же эффективно, как и для встроенного метода.

Ответ 5

Если вам нужно выполнить много операций добавления для создания большой строки, вы можете использовать StringIO или cStringIO. Интерфейс похож на файл. то есть: вы write, чтобы добавить текст к нему.

Если вы просто добавляете две строки, просто используйте +.

Ответ 6

это действительно зависит от вашего приложения. Если вы перебираете сотни слов и хотите добавить их в список, лучше .join(). Но если вы собрали длинное предложение, вам лучше использовать +=.

Ответ 7

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

Ответ 8

В принципе, никакой разницы. Единственная постоянная тенденция заключается в том, что Python, кажется, становится все медленнее с каждой версией...: (


List

%%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 s за цикл

Python 3.4

1, лучше всего 3: 7.99 s за цикл

Python 3.5

1, лучше всего 3: 8.48 s за цикл

Python 3.6

1, лучше всего 3: 9.93 s за цикл


Строка

%%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 s за цикл

Python 3.5

1, лучше всего 3: 8.82 s за цикл

Python 3.6

1, лучше всего 3: 9.24 s за цикл

Ответ 9

a='foo'
b='baaz'

a.__add__(b)

out: 'foobaaz'

Ответ 10

добавлять строки с помощью функции __add__ function

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

Выход

Hello World