Python 3 bytes formatting

Question:

In Python 3, one can format a string like:

"{0}, {1}, {2}".format(1, 2, 3)

But how to format bytes?

b"{0}, {1}, {2}".format(1, 2, 3)

raises AttributeError: 'bytes' object has no attribute 'format'.

If there is no format method for bytes, how to do the formatting or “rewriting” of bytes?

Asked By: Ecir Hana

||

Answers:

Interestingly .format() doesn’t appear to be supported for byte-sequences; as you have demonstrated.

You could use .join() as suggested here: http://bugs.python.org/issue3982

b", ".join([b'1', b'2', b'3'])

There is a speed advantage associated with .join() over using .format() shown by the BDFL himself: http://bugs.python.org/msg180449

Answered By: mechanical_meat

Another way would be:

"{0}, {1}, {2}".format(1, 2, 3).encode()

Tested on IPython 1.1.0 & Python 3.2.3

Answered By: Schcriher

As of Python 3.5, % formatting will work for bytes, too!

This was part of PEP 461, authored by Ethan Furman:

PEP: 461
Title: Adding % formatting to bytes and bytearray
Version: $Revision$
Last-Modified: $Date$
Author: Ethan Furman <ethan at stoneleaf.us>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 2014-01-13
Python-Version: 3.5
Post-History: 2014-01-14, 2014-01-15, 2014-01-17, 2014-02-22, 2014-03-25,
               2014-03-27
Resolution:


Abstract
========

This PEP proposes adding % formatting operations similar to Python 2's ``str``
type to ``bytes`` and ``bytearray`` [1]_ [2]_.


Rationale
=========

While interpolation is usually thought of as a string operation, there are
cases where interpolation on ``bytes`` or ``bytearrays`` make sense, and the
work needed to make up for this missing functionality detracts from the overall
readability of the code.


Motivation
==========

With Python 3 and the split between ``str`` and ``bytes``, one small but
important area of programming became slightly more difficult, and much more
painful -- wire format protocols [3]_.

This area of programming is characterized by a mixture of binary data and
ASCII compatible segments of text (aka ASCII-encoded text).  Bringing back a
restricted %-interpolation for ``bytes`` and ``bytearray`` will aid both in
writing new wire format code, and in porting Python 2 wire format code.

Common use-cases include ``dbf`` and ``pdf`` file formats, ``email``
formats, and ``FTP`` and ``HTTP`` communications, among many others.

PEP 461 was accepted by Guido van Rossum on March 27, 2014:

Accepted. Congrats with marshalling yet another quite contentious
discussion, and putting up with my last-minute block-headedness!

From this, we can obviously conclude that % is no longer scheduled for deprecation (as was announced with Python 3.1).

Answered By: Ecir Hana

I found the %b working best in Python 3.6.2, it should work both for b”” and “”:

print(b"Some stuff %b. Some other stuff" % my_byte_or_unicode_string)
Answered By: Ivan Bilan

I’ve found this to work.

a = "{0}, {1}, {2}".format(1, 2, 3)

b = bytes(a, encoding="ascii")

>>> b
b'1, 2, 3'
Answered By: binny

For Python 3.6+ you can use this nice and clean syntax:

f'foo {bar}'.encode() # a byte string
Answered By: Nurbol Alpysbayev

b|"Hello {0}!".format("World")

#!/usr/bin/env python3.9
# -*- coding: utf-8 -*-

import builtins


class bytes(bytes):
    def format(self, *args, encoding: str = "utf-8") -> builtins.bytes:
        return_value: bytes = self

        for arg, i in zip(args, range(len(args))):
            pattern: bytes = f"{i}".encode(encoding=encoding)
            return_value = return_value.replace(pattern, bytes(arg, encoding=encoding))

        return return_value

    def __or__(self, other):
        return bytes(self + bytes(other, encoding="utf-8"))


b = bytes('', encoding="utf-8")


if __name__ == '__main__':   
    print( b|"Hello {0} {1}".format("World", "!") )
Answered By: Felix