Python 3

From the docs:

Concatenating immutable sequences always results in a new object. This means that building up a sequence by repeated concatenation will have a quadratic runtime cost in the total sequence length. To get a linear runtime cost, you must switch to one of the alternatives below: if concatenating str objects, you can build a list and use str.join() at the end or else write to an io.StringIO instance and retrieve its value when complete

Experiment to compare runtime of several options:

import sys
import timeit
from io import StringIO
from array import array


def test_concat():
    out_str = ''
    for _ in range(loop_count):
        out_str += 'abc'
    return out_str


def test_join_list_loop():
    str_list = []
    for _ in range(loop_count):
        str_list.append('abc')
    return ''.join(str_list)


def test_array():
    char_array = array('b')
    for _ in range(loop_count):
        char_array.frombytes(b'abc')
    return str(char_array.tostring())


def test_string_io():
    file_str = StringIO()
    for _ in range(loop_count):
        file_str.write('abc')
    return file_str.getvalue()


def test_join_list_compr():
    return ''.join(['abc' for _ in range(loop_count)])


def test_join_gen_compr():
    return ''.join('abc' for _ in range(loop_count))


loop_count = 80000

print(sys.version)

res = {}

for k, v in dict(globals()).items():
    if k.startswith('test_'):
        res[k] = timeit.timeit(v, number=10)

for k, v in sorted(res.items(), key=lambda x: x[1]):
    print('{:.5f} {}'.format(v, k))

results

3.7.5 (default, Nov  1 2019, 02:16:32) 
[Clang 11.0.0 (clang-1100.0.33.8)]
0.03738 test_join_list_compr
0.05681 test_join_gen_compr
0.09425 test_string_io
0.09636 test_join_list_loop
0.11976 test_concat
0.19267 test_array

Python 2

Efficient String Concatenation in Python is a rather old article and its main statement that the naive concatenation is far slower than joining is not valid anymore, because this part has been optimized in CPython since then. From the docs:

CPython implementation detail: If s and t are both strings, some Python implementations such as CPython can usually perform an in-place optimization for assignments of the form s = s + t or s += t. When applicable, this optimization makes quadratic run-time much less likely. This optimization is both version and implementation dependent. For performance sensitive code, it is preferable to use the str.join() method which assures consistent linear concatenation performance across versions and implementations.

I've adapted their code a bit and got the following results on my machine:

from cStringIO import StringIO
from UserString import MutableString
from array import array

import sys, timeit

def method1():
    out_str = ''
    for num in xrange(loop_count):
        out_str += `num`
    return out_str

def method2():
    out_str = MutableString()
    for num in xrange(loop_count):
        out_str += `num`
    return out_str

def method3():
    char_array = array('c')
    for num in xrange(loop_count):
        char_array.fromstring(`num`)
    return char_array.tostring()

def method4():
    str_list = []
    for num in xrange(loop_count):
        str_list.append(`num`)
    out_str = ''.join(str_list)
    return out_str

def method5():
    file_str = StringIO()
    for num in xrange(loop_count):
        file_str.write(`num`)
    out_str = file_str.getvalue()
    return out_str

def method6():
    out_str = ''.join([`num` for num in xrange(loop_count)])
    return out_str

def method7():
    out_str = ''.join(`num` for num in xrange(loop_count))
    return out_str


loop_count = 80000

print sys.version

print 'method1=', timeit.timeit(method1, number=10)
print 'method2=', timeit.timeit(method2, number=10)
print 'method3=', timeit.timeit(method3, number=10)
print 'method4=', timeit.timeit(method4, number=10)
print 'method5=', timeit.timeit(method5, number=10)
print 'method6=', timeit.timeit(method6, number=10)
print 'method7=', timeit.timeit(method7, number=10)

Results:

2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
method1= 0.171155929565
method2= 16.7158739567
method3= 0.420584917068
method4= 0.231794118881
method5= 0.323612928391
method6= 0.120429992676
method7= 0.145267963409

Conclusions:

  • join still wins over concat, but marginally
  • list comprehensions are faster than loops (when building a list)
  • joining generators is slower than joining lists
  • other methods are of no use (unless you're doing something special)
🌐
Kodeclik
kodeclik.com › python-string-buffer
Python String Buffer
October 16, 2024 - A string buffer in Python is an object that holds a sequence of characters, allowing us to manipulate and modify strings efficiently. It serves as a temporary storage space for building or modifying strings, without incurring the overhead of ...
Top answer
1 of 11
123

Python 3

From the docs:

Concatenating immutable sequences always results in a new object. This means that building up a sequence by repeated concatenation will have a quadratic runtime cost in the total sequence length. To get a linear runtime cost, you must switch to one of the alternatives below: if concatenating str objects, you can build a list and use str.join() at the end or else write to an io.StringIO instance and retrieve its value when complete

Experiment to compare runtime of several options:

import sys
import timeit
from io import StringIO
from array import array


def test_concat():
    out_str = ''
    for _ in range(loop_count):
        out_str += 'abc'
    return out_str


def test_join_list_loop():
    str_list = []
    for _ in range(loop_count):
        str_list.append('abc')
    return ''.join(str_list)


def test_array():
    char_array = array('b')
    for _ in range(loop_count):
        char_array.frombytes(b'abc')
    return str(char_array.tostring())


def test_string_io():
    file_str = StringIO()
    for _ in range(loop_count):
        file_str.write('abc')
    return file_str.getvalue()


def test_join_list_compr():
    return ''.join(['abc' for _ in range(loop_count)])


def test_join_gen_compr():
    return ''.join('abc' for _ in range(loop_count))


loop_count = 80000

print(sys.version)

res = {}

for k, v in dict(globals()).items():
    if k.startswith('test_'):
        res[k] = timeit.timeit(v, number=10)

for k, v in sorted(res.items(), key=lambda x: x[1]):
    print('{:.5f} {}'.format(v, k))

results

3.7.5 (default, Nov  1 2019, 02:16:32) 
[Clang 11.0.0 (clang-1100.0.33.8)]
0.03738 test_join_list_compr
0.05681 test_join_gen_compr
0.09425 test_string_io
0.09636 test_join_list_loop
0.11976 test_concat
0.19267 test_array

Python 2

Efficient String Concatenation in Python is a rather old article and its main statement that the naive concatenation is far slower than joining is not valid anymore, because this part has been optimized in CPython since then. From the docs:

CPython implementation detail: If s and t are both strings, some Python implementations such as CPython can usually perform an in-place optimization for assignments of the form s = s + t or s += t. When applicable, this optimization makes quadratic run-time much less likely. This optimization is both version and implementation dependent. For performance sensitive code, it is preferable to use the str.join() method which assures consistent linear concatenation performance across versions and implementations.

I've adapted their code a bit and got the following results on my machine:

from cStringIO import StringIO
from UserString import MutableString
from array import array

import sys, timeit

def method1():
    out_str = ''
    for num in xrange(loop_count):
        out_str += `num`
    return out_str

def method2():
    out_str = MutableString()
    for num in xrange(loop_count):
        out_str += `num`
    return out_str

def method3():
    char_array = array('c')
    for num in xrange(loop_count):
        char_array.fromstring(`num`)
    return char_array.tostring()

def method4():
    str_list = []
    for num in xrange(loop_count):
        str_list.append(`num`)
    out_str = ''.join(str_list)
    return out_str

def method5():
    file_str = StringIO()
    for num in xrange(loop_count):
        file_str.write(`num`)
    out_str = file_str.getvalue()
    return out_str

def method6():
    out_str = ''.join([`num` for num in xrange(loop_count)])
    return out_str

def method7():
    out_str = ''.join(`num` for num in xrange(loop_count))
    return out_str


loop_count = 80000

print sys.version

print 'method1=', timeit.timeit(method1, number=10)
print 'method2=', timeit.timeit(method2, number=10)
print 'method3=', timeit.timeit(method3, number=10)
print 'method4=', timeit.timeit(method4, number=10)
print 'method5=', timeit.timeit(method5, number=10)
print 'method6=', timeit.timeit(method6, number=10)
print 'method7=', timeit.timeit(method7, number=10)

Results:

2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
method1= 0.171155929565
method2= 16.7158739567
method3= 0.420584917068
method4= 0.231794118881
method5= 0.323612928391
method6= 0.120429992676
method7= 0.145267963409

Conclusions:

  • join still wins over concat, but marginally
  • list comprehensions are faster than loops (when building a list)
  • joining generators is slower than joining lists
  • other methods are of no use (unless you're doing something special)
2 of 11
15

Depends on what you want to do. If you want a mutable sequence, the builtin list type is your friend, and going from str to list and back is as simple as:

 mystring = "abcdef"
 mylist = list(mystring)
 mystring = "".join(mylist)

If you want to build a large string using a for loop, the pythonic way is usually to build a list of strings then join them together with the proper separator (linebreak or whatever).

Else you can also use some text template system, or a parser or whatever specialized tool is the most appropriate for the job.

Discussions

java - String's substring function vs StringBuffer's substring function - Stack Overflow
I went through the String and StringBuffer API and it seems both works same internally when you call the substring method. Both have a ref to original char array (char[] original), so both are usin... More on stackoverflow.com
🌐 stackoverflow.com
[Python] Is there an inherent difference with a ctypes string buffer that makes it a bad idea to use to store byte data?
If you have a ctypes array called data, the direct way to access its individual elements is by just referring to data[0]. In the specific case of a c_char array, which is what create_string_buffer gives you, there's also a special data.value property which interprets the contents of the array as a C-style byte string. That is, it only reads up to the first null byte, and converts everything up to that point into a Python bytes objects. So if you don't want to treat your buffer as null-terminated, then simply don't use the value property. More on reddit.com
🌐 r/learnprogramming
3
1
November 8, 2024
java - Use StringBuffer to replace substring throughout a long string - Stack Overflow
I need to compose a long string (4324 characters) and want to use StringBuffer for this purpose. Most of the string will be whitespace but some portions contain orderdetails. They must appear at ce... More on stackoverflow.com
🌐 stackoverflow.com
How do I get a substring of a string in Python? - Stack Overflow
Substr() normally (i.e. PHP and Perl) works this way: ... So the parameters are beginning and LENGTH. But Python's behaviour is different; it expects beginning and one after END (!). This is difficult to spot by beginners. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Python Adventures
pythonadventures.wordpress.com › tag › stringbuffer
stringbuffer – Python Adventures
Categories: python Tags: concatenate, java, string, stringbuffer, stringbuilder, StringIO
🌐
GeeksforGeeks
geeksforgeeks.org › java › stringbuffer-substring-method-in-java-with-examples
StringBuffer substring() method in Java with Examples - GeeksforGeeks
July 30, 2019 - The substring(int start) method of StringBuffer class is the inbuilt method used to return a substring start from index start and extends to end of this sequence. The string returned by this method contains all character from index start to ...
🌐
Haxe
api.haxe.org › StringBuf.html
StringBuf - Haxe 4.3.7 API
If len is omitted or null, the substring ranges from pos to the end of s.
🌐
Wordpress
code2blog.wordpress.com › 2019 › 11 › 26 › python-equivalent-of-java-stringbuffer
Private Site
November 26, 2019 - Build a website. Sell your stuff. Write a blog. And so much more · This site is currently private. Log in to WordPress.com to request access
🌐
TutorialsPoint
tutorialspoint.com › python-program-to-clear-the-string-buffer
Python Program to Clear the String Buffer
In Python, we can clear the string buffer by assigning an empty string to the buffer and using Python's inbuilt reset() method. A string buffer is a mutable sequence of characters. These characters can be modified according to the requirements. The string buffer can be modified or cleared before ...
Find elsewhere
🌐
W3Schools
w3schools.com › python › python_strings.asp
Python Strings
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
🌐
Tutorialspoint
tutorialspoint.com › java › lang › stringbuffer_substring.htm
Java StringBuffer substring() Method
Python TechnologiesDatabasesComputer ... Categories ... The Java StringBuffer substring() method is, used to retrieve a desired subsequence from a StringBuffer object....
🌐
w3grads
w3grads.com › blog › get-substring-out-of-string-in-python
Get substring out of string in Python - W3grads blog
This blogs guides you on how you can strip out certain values from lists or getting a substring of characters from a string in python.
🌐
Stackabyte
stackabyte.com › tutorials › Java › java-stringbuilder-stringbuffer-guide
Java StringBuilder & StringBuffer | Stack a Byte
May 15, 2025 - StringBuilder builder = new StringBuilder("Hello"); // Append (most commonly used) builder.append(" World"); // "Hello World" builder.append(123); // "Hello World123" builder.append(true); // "Hello World123true" // Insert at specific position builder.insert(5, " Java"); // "Hello Java World123true" // Delete characters builder.delete(11, 16); // "Hello Java true" // Replace a range of characters builder.replace(6, 10, "Python"); // "Hello Python true" // Reverse the characters builder.reverse(); // "eurt nohtyP olleH" // Set length (truncate or expand with null characters) builder.setLength(10); // "eurt nohty" // Get character at index char c = builder.charAt(0); // 'e' // Get substring String sub = builder.substring(0, 4); // "eurt" // Convert to String String result = builder.toString(); // "eurt nohty"
🌐
Reddit
reddit.com › r/learnprogramming › [python] is there an inherent difference with a ctypes string buffer that makes it a bad idea to use to store byte data?
r/learnprogramming on Reddit: [Python] Is there an inherent difference with a ctypes string buffer that makes it a bad idea to use to store byte data?
November 8, 2024 -

(as opposed to doing something similar natively in C)

Running into an issue where a function in a DLL expects an unsigned char * as a buffer to byte data (specifically this function reads one byte from a device and stores that byte in the passed in data buffer). So I do ctypes.create_string_buffer(size) and pass that in as the data arg to this DLL function. This works sometimes, but I just spent some time debugging why it doesn't work at times, and it seems to be because when the data being read and set has a value of 0, this causes some weird behavior where this string buffer (which I know is actually a ctypes array of c_chars, but string buffer is more concise) then treats this value as a null character, and therefore goes wacky, specifically when I try to access that byte via `data.value[0]` (this causes an index out of range error). If the byte being read and set is any other value, it seems to work fine and 0 is a valid index into this string buffer.

I don't have a full 100% grasp on what's going on here, but it *seems* like there's just something under the hood with how these string buffers are used. I think in C these issues don't exist because if you're using a buffer of chars to store byte data rather than characters, then you won't ever really parse the bytes as a string and therefore the value of 0 anywhere in the buffer won't cause weird issues.

But I guess in ctypes/python it's different? Just wanted to get other opinions here to see if my current understanding is correct or at least headed in the right direction.

Let me know if anything isn't clear!

🌐
LWN.net
lwn.net › Articles › 816415
Reworking StringIO concatenation in Python [LWN.net]
April 1, 2020 - These results can be summarized as follows: of more than half-dozen Python implementations, CPython3 is the only implementation which optimizes for the dubious usage of an immutable string type as an accumulating character buffer.
🌐
Read the Docs
stackless.readthedocs.io › en › 2.7-slp › library › stringio.html
7.5. StringIO — Read and write strings as files — Stackless-Python 2.7.15 documentation
This module implements a file-like class, StringIO, that reads and writes a string buffer (also known as memory files). See the description of file objects for operations (section File Objects). (For standard strings, see str and unicode.) · When a StringIO object is created, it can be initialized ...
🌐
University of Texas
cs.utexas.edu › ~mitra › csSummer2012 › cs312 › lectures › strings.html
String and StringBuffer
int indexOf ( String str ) : returns the index of the first occurrence of the substring str or -1 if the substring does not exist.
🌐
w3resource
w3resource.com › python-exercises › os › python-os-exercise-16.php
Python: Write a string to a buffer and retrieve the value written, at the end discard buffer memory - w3resource
August 11, 2025 - Python Exercises, Practice and Solution: Write a Python program to write a string to a buffer and retrieve the value written, at the end discard buffer memory.
🌐
BeginnersBook
beginnersbook.com › 2014 › 08 › stringbuffer-substring-method-example
Java – StringBuffer substring method Example
October 9, 2022 - startIndex: Specifies the start position of the substring ... If startIndex < 0 or >= length of the string represented by StringBuffer.