84

I'm looking for a formatted byte string literal. Specifically, something equivalent to

name = "Hello"
bytes(f"Some format string {name}")

Possibly something like fb"Some format string {name}".

Does such a thing exist?

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
Enrico Borba
  • 1,877
  • 2
  • 14
  • 26
  • 7
    I don't think so. `bytes` don't even have a `.format` method, so, I'd be surprised if they had f-string equivalents. The closest you'll get is [bytes formatting](https://docs.python.org/3/library/stdtypes.html#printf-style-bytes-formatting) – juanpa.arrivillaga Jul 27 '17 at 20:33

6 Answers6

69

No. The idea is explicitly dismissed in the PEP:

For the same reason that we don't support bytes.format(), you may not combine 'f' with 'b' string literals. The primary problem is that an object's __format__() method may return Unicode data that is not compatible with a bytes string.

Binary f-strings would first require a solution for bytes.format(). This idea has been proposed in the past, most recently in PEP 461. The discussions of such a feature usually suggest either

  • adding a method such as __bformat__() so an object can control how it is converted to bytes, or

  • having bytes.format() not be as general purpose or extensible as str.format().

Both of these remain as options in the future, if such functionality is desired.

jwodder
  • 54,758
  • 12
  • 108
  • 124
31

In 3.6+ you can do:

>>> a = 123
>>> f'{a}'.encode()
b'123'
johnson
  • 3,729
  • 3
  • 31
  • 32
  • 6
    If you want to use bytes format, it's probably because the data you want to format (`a` here) is bytes. Decoding that to (potentially invalid) unicode and then going back to bytes is asking for trouble. – Chris L. Barnes Jan 20 '21 at 15:00
  • 3
    It's not potentially invalid, it's most likely not what you want: If `a`was of type `bytes` then `f{a}.encode()` would give `b"b'123'"` – johnson Jan 21 '21 at 16:46
9

You were actually super close in your suggestion; if you add an encoding kwarg to your bytes() call, then you get the desired behavior:

>>> name = "Hello"
>>> bytes(f"Some format string {name}", encoding="utf-8")

b'Some format string Hello'

Caveat: This works in 3.8 for me, but note at the bottom of the Bytes Object headline in the docs seem to suggest that this should work with any method of string formatting in all of 3.x (using str.format() for versions <3.6 since that's when f-strings were added, but the OP specifically asks about 3.6+).

dayofthepenguin
  • 139
  • 1
  • 6
7

From python 3.6.2 this percent formatting for bytes works for some use cases:

print(b"Some stuff %a. Some other stuff" % my_byte_or_unicode_string)

But as AXO commented:

This is not the same. %a (or %r) will give the representation of the string, not the string iteself. For example b'%a' % b'bytes' will give b"b'bytes'", not b'bytes'.

Which may or may not matter depending on if you need to just present the formatted byte_or_unicode_string in a UI or if you potentially need to do further manipulation.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Bob Jordan
  • 3,049
  • 2
  • 34
  • 41
  • This is not the same. `%a` (or `%r`) will give the representation of the string, not the string iteself. For example `b'%a' % b'bytes'` will give `b"b'bytes'"`, not `b'bytes'`. – AXO Jun 28 '19 at 15:22
  • I think you meant `%s` and `my_byte_string`, e.g. following AXO's example, `b'%s' % b'bytes'` -> `b'bytes'` – wjandrea Aug 18 '20 at 13:53
  • Documentation is at https://docs.python.org/3/library/stdtypes.html#printf-style-bytes-formatting . Note that `%b` is more explicit than `%s` for formatting a `bytes` argument. – user202729 Jun 04 '23 at 03:52
1

As noted here, you can format this way:

>>> name = b"Hello"
>>> b"Some format string %b World" % name
b'Some format string Hello World'

You can see more details in PEP 461

Note that in your example you could simply do something like:

>>> name = b"Hello"
>>> b"Some format string " + name
b'Some format string Hello'
-5

This was one of the bigger changes made from python 2 to python3. They handle unicode and strings differently.

This s how you'd convert to bytes.

string = "some string format"
string.encode()
print(string)

This is how you'd decode to string.

string.decode()

I had a better appreciation for the difference between Python 2 versus 3 change to unicode through this coursera lecture by Charles Severence. You can watch the entire 17 minute video or fast forward to somewhere around 10:30 if you want to get to the differences between python 2 and 3 and how they handle characters and specifically unicode.

I understand your actual question is how you could format a string that has both strings and bytes.

inBytes = b"testing"
inString = 'Hello'
type(inString) #This will yield <class 'str'>
type(inBytes) #this will yield <class 'bytes'>

Here you could see that I have a string a variable and a bytes variable.

This is how you would combine a byte and string into one string.

formattedString=(inString + ' ' + inBytes.encode())
Dom DaFonte
  • 1,619
  • 14
  • 31
  • 18
    I appreciate your time and efforts, but your answer is irrelevant to the question. – GIZ Jul 27 '17 at 20:57
  • 1
    I understood Enrico's question specifically how he could convert bytes and strings in Python 3, an area which changed significantly in the new version. My answer was meant to help him understand how that change happened and how he could handle a similar operation in Python 3. That's why I feel this response is relevant to his question. – Dom DaFonte Jul 27 '17 at 21:48