The correct answer is:

p.communicate(b"insert into egg values ('egg')")

Note the leading b, telling you that it's a string of bytes, not a string of unicode characters. Also, if you are reading this from a file:

value = open('thefile', 'rt').read()
p.communicate(value)

The change that to:

value = open('thefile', 'rb').read()
p.communicate(value)

Again, note the 'b'. Now if your value is a string you get from an API that only returns strings no matter what, then you need to encode it.

p.communicate(value.encode('latin-1'))

Latin-1, because unlike ASCII it supports all 256 bytes. But that said, having binary data in unicode is asking for trouble. It's better if you can make it binary from the start.

Answer from Lennart Regebro on Stack Overflow
🌐
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
See the description of file objects for operations (section File Objects). (For standard strings, see str and unicode.) class StringIO.StringIO([buffer])¶ · When a StringIO object is created, it can be initialized to an existing string by passing the string to the constructor.
Discussions

node.js - Nodejs InputStream Buffer convert to string using python - Stack Overflow
i have one application nodejs which request send to python using python-shell npm package. and python script read data and parse string. nodejs file : teststr.js let buf = ` 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
String buffer to be filled by native side
Several places in the httpd expect that the user first requests a length and then provides a char * buffer with matching space. I would like to provide a bytearray or similar as the buffer. But MP expects a string when the parameter was a char *. My current solution looks like this: def ... More on forum.lvgl.io
🌐 forum.lvgl.io
0
0
February 4, 2021
vim : how to set current buffer to a string using `:python` - Vi and Vim Stack Exchange
As example, my current buffer contains below lines di=01;34 ln=01;36 mh=00 pi=40;33 I want to join all lines with :, and set entire buffer to the joined string. How to achieve that, using :python More on vi.stackexchange.com
🌐 vi.stackexchange.com
September 21, 2019
🌐
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 - Write a Python program to use an in-memory buffer to temporarily store text, print the content, and then demonstrate that the buffer is empty after discarding.
🌐
Kodeclik
kodeclik.com › python-string-buffer
Python String Buffer
October 16, 2024 - Now that we have that out of the way, what is a string buffer? A string buffer in Python is an object that holds a sequence of characters, allowing us to manipulate and modify strings efficiently.
🌐
Stack Overflow
stackoverflow.com › questions › 47467343 › nodejs-inputstream-buffer-convert-to-string-using-python › 47468116
node.js - Nodejs InputStream Buffer convert to string using python - Stack Overflow
Copylet buf = `<html><body><p>Reply</p></body></html>` var PythonShell = require('python-shell') var options = { mode: 'binary', args: ['html'], scriptPath: __dirname + '/', pythonPath: '/usr/bin/python3' } var pyshell = new PythonShell('test.py', options) pyshell.stdout.on('data', function (message) { console.log(message) }) pyshell.send(buf) pyshell.end(function (err) { if (err) { console.log('End Script' + err) } }) ... Copyimport sys import base64 import struct import io type = sys.argv[1] html = "" htmlBuffer = "" for line in sys.stdin.buffer: htmlBuffer = io.BufferedReader(line) #htmlBuffer = to_str(htmlBuffer) #htmlBuffer.decode('utf-8', errors='ignore').strip() print("%s" % (htmlBuffer))
🌐
Python
docs.python.org › 2.0 › api › bufferObjects.html
7.2.3 Buffer Objects
A ``buffer object'' is defined in the bufferobject.h header (included by Python.h). These objects look very similar to string objects at the Python programming level: they support slicing, indexing, concatenation, and some other standard string operations.
🌐
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!

Find elsewhere
🌐
Python
docs.python.org › 3 › c-api › buffer.html
Buffer Protocol — Python 3.14.8 documentation
Certain objects available in Python wrap access to an underlying memory array or buffer. Such objects include the built-in bytes and bytearray, and some extension types like array.array. Third-part...
🌐
LVGL Forum
forum.lvgl.io › micropython
String buffer to be filled by native side - Micropython - LVGL Forum
February 4, 2021 - Several places in the httpd expect that the user first requests a length and then provides a char * buffer with matching space. I would like to provide a bytearray or similar as the buffer. But MP expects a string when the parameter was a char *. My current solution looks like this: def ...
🌐
Bun
bun.sh › guides › binary data › buffer to string
Convert a Buffer to a string | Bun Guides
The Buffer class provides a .toString() method that converts a Buffer to a string.
🌐
Python Forum
python-forum.io › thread-41896.html
the quest for a mutable string (buffer)
April 4, 2024 - so often i am taking some logic from some program not in Python and need to implement it in Python. so many of these programs are constructing strings by putting string parts in over other string parts to end up with the desired result as a mutated ...
🌐
Python Adventures
pythonadventures.wordpress.com › tag › stringbuffer
stringbuffer – Python Adventures
Use a StringIO object and print to it. In short: from cStringIO import StringIO out = StringIO() print >>out, 'arbitrary text' # 'out' behaves like a file return out.getvalue() Categories: python Tags: concatenate, java, string, stringbuffer, stringbuilder, StringIO
Top answer
1 of 2
1

In my day job, I wrote the software for an embedded system and a PC communicating with each other by a USB cable, using the UART protocol at 115,200 baud.

I see that you tagged your post with PySerial, so you already know about Python's most popular package for serial port communication. I will add that if you are using PyQt, there's a serial module included in that package as well.

115,200 baud is not fast for a modern desktop PC. I doubt that any parsing you do on the PC side will fail to keep up. I parse data streams and plot graphs of my data in real time using PyQt.

What I have noticed in my work with communication between an embedded system and a PC over a UART is that some data gets corrupted occasionally. A byte can be garbled, repeated, or dropped. Also, even if no bytes are added or dropped, you can occasionally perform a read while only part of a packet is in the buffer, and the read will terminate early. If you use a fixed read length of 40 bytes and trust that each read will always line up exactly with a data packet as you show above, you will frequently be wrong.

To solve these kinds of problems, I wrote a FIFO class in Python which consumes serial port data at the head of the FIFO, yields valid data packets at the tail, and discards invalid data. My FIFO holds 3 times as many bytes as my data packets, so if I am looking for packet boundaries using specific sequences, I have plenty of signposts.

A few more recommendations: work in Python 3 if you have the choice, it's cleaner. Use bytes and bytearray objects. Don't use str, because you will find yourself converting back and forth between Unicode and ASCII.

2 of 2
0

This format is almost parseable as a csv, but not quite, because the fourth field is JSON, and you may not be able to guarantee that the JSON doesn't contain any strings with embedded semicolons. So, I think you probably want to just use string (or, rather, bytes) manipulation functions:

def parsemsg(buf):
    s, cmd, length, rest = buf.split(b';', 3)
    j, _, e = rest.rpartition(b';')
    if s != b'S' or e != b'E':
        raise ValueError('must start with S and end with E')
    return cmd.decode('utf-8'), int(length), json.loads(j)

Then:

>>> parsemsg(b'S,SEND,40,{"ID":"asg01","T":1,"P":{"T":180}},E')
('SEND', 40, {'ID': 'asg01', 'T': 1, 'P': {'T': 180}})

The actual semicolon-parsing part takes 602ns on my laptop, The decode and int raise that to 902ns. The json.loads, on the other hand, takes 10us. So, if you're worried about performance, the JSON part is really the only part that matters (trying third-party JSON libs I happen to have installed, the fastest one is still 8.1us, which isn't much better). You might as well keep everything else simple and robust.

Also, considering that you're reading this at 115000 baud, you can't get these messages any faster than about 6ms, so spending 11us parsing them is not even close to a problem in the first place.

Top answer
1 of 1
1

Here's a slightly better way. Cast the pointer to (single) wchar to a pointer to an array of wchar. Then you can dereference and write the value directly to the array:

def callback(pt: POINTER(c_wchar), ptsize: c_size_t) -> None:
    pa = cast(pt,POINTER(c_wchar * ptsize))
    pa.contents.value = 'python string'

This also has the advantage that if you write more that ptsize characters to the array, Python will throw an exception. For example:

def callback(pt: POINTER(c_wchar), ptsize: c_size_t) -> None:
    s = 'a' * (ptsize + 1)  # one too big
    pa = cast(pt,POINTER(c_wchar * ptsize))
    pa.contents.value = s

This results in:

Exception ignored on calling ctypes callback function: <function callback at 0x0000020B1C7F6310>
Traceback (most recent call last):
  File "C:\test.py", line 13, in callback
    pa.contents.value = s
ValueError: string too long

Be careful of the null termination, though. Python only writes it via .value if it has room in the array. Here's a demo:

test.cpp

#include <iostream>
#include <stdio.h>

using namespace std;

typedef void(__stdcall* Mycallback2)(wchar_t* buff, size_t buffsize);

extern "C" __declspec(dllexport)
void TestMethod5(Mycallback2 callback)
{
    wchar_t* buff = new wchar_t[7];        // length 7 buffer
    swprintf_s(buff, 7, L"%s", L"123456"); // init buffer
    if (callback) callback(buff, 5);       // callback alters only 5
    wcout << L'|' << buff << L'|' << endl;
    delete[] buff;
}

test.py

from ctypes import *

dll = CDLL('./test')

MYCALLBACKTYPE = CFUNCTYPE(None, POINTER(c_wchar), c_size_t)
dll.TestMethod5.restype = None
dll.TestMethod5.argtypes = [MYCALLBACKTYPE]

def callback(pt: POINTER(c_wchar), ptsize: c_size_t) -> None:
    s = 'a' * (ptsize if demo else ptsize-1) # 4 or 5 'a' string, no explicit null
    pa = cast(pt,POINTER(c_wchar * ptsize))
    print('pt =',pa.contents.value)
    pa.contents.value = s

mycallback = MYCALLBACKTYPE(callback)
demo = 0
dll.TestMethod5(mycallback)
demo = 1
dll.TestMethod5(mycallback)

Output:

pt = 12345         # only "sees" the size reported
|aaaa|             # null was written since there was room
pt = 12345
|aaaaa6|           # null wasn't written when length 5 value written,
                   # So wcout "saw" the ending 6.
🌐
Python Module of the Week
pymotw.com › 2 › StringIO
StringIO and cStringIO – Work with text buffers using file-like API - Python Module of the Week
The cStringIO version is written in C for speed, while StringIO is written in Python for portability. Using cStringIO to build large strings can offer performance savings over some other string conctatenation techniques. Here are some pretty standard, simple, examples of using StringIO buffers:
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.

🌐
DEV Community
dev.to › pgradot › sharing-strings-between-c-and-python-through-byte-buffers-1nj0
Sharing strings between C and Python through byte buffers - DEV Community
June 17, 2020 - An extra zero byte is reserved at the end to ensure it is zero-terminated, but a size is present so strings with null bytes in them can be represented. String representation in Python is different and more complex than in C. I have an IoT device with Bluetooth Low Energy (BLE) connectivity. Bluetooth Low Energy devices transfer data back and forth using concepts called "services" and "characteristics". One of my characteristics is a buffer to share a string: 20 bytes with the name of my device.