Question
Python accepts a b prefix before a string literal:
b"The string"
What does the b prefix mean? What effects does it have, and when is it appropriate to use it?
How does it differ from the u prefix for Unicode strings? Are there other prefixes that can be placed before Python string literals?
Short Answer
The b prefix creates a bytes literal rather than a normal Python text string. You will learn the difference between str and bytes, how to convert between them with encoding and decoding, when byte data is necessary, and which literal prefixes Python supports.
Concept
In modern Python, a normal quoted literal creates a str object:
message = "Hello"
print(type(message)) # <class 'str'>
A literal prefixed with b creates a bytes object:
message_bytes = b"Hello"
print(type(message_bytes)) # <class 'bytes'>
str represents text: human-readable characters such as letters, punctuation, and emoji. Python stores text as Unicode characters.
bytes represents raw byte values: integers from 0 through 255. Bytes are the form used by files, network connections, images, compressed data, and many binary protocols.
print("ABC") # ABC
print(b"ABC") # b'ABC'
print(list(b"ABC")) # [65, 66, 67]
The b is not part of the value. It is literal syntax that tells Python which type to create.
A bytes literal can directly contain ASCII characters. For byte values that are not easily written as ASCII, use escape sequences such as \x00:
packet_start = b"\x02DATA\x03"
Use str for text and bytes for byte-oriented data. Convert explicitly at a boundary using an encoding, usually UTF-8:
text = "café"
data = text.encode("utf-8") # str -> bytes
again = data.decode("utf-8") # bytes -> str
Explicit conversion matters because the same byte sequence can mean different text under different encodings.
Mental Model
Think of str as a written message and bytes as the individual numbered signals used to send or store that message.
str: “Hello” as text a person can read.bytes: the numeric byte values a computer sends across a network or writes to a file.
The b prefix says: “Create the raw signals, not a text message.”
Encoding is translating a message into signals. Decoding is translating those signals back into a message.
Syntax and Examples
A bytes literal uses b or uppercase B immediately before the quote:
data1 = b"hello"
data2 = b'hello'
data3 = B"hello"
Bytes support many familiar escape sequences:
newline = b"first line\nsecond line"
header = b"ID:\x00\xff"
You can inspect byte values by iterating over the object:
word = b"cat"
for value in word:
print(value)
Output:
99
97
116
Unlike iterating over a str, iterating over bytes produces integers.
Encoding text into bytes
name = "Ada"
wire_data = name.encode("utf-8")
print(wire_data) # b'Ada'
print(type(wire_data)) # <class 'bytes'>
Decoding bytes into text
wire_data = b"Ada"
name = wire_data.decode("utf-8")
print(name) # Ada
print(type(name)) # <class 'str'>
Use encode() when text must become bytes, and decode() when bytes contain encoded text.
Step by Step Execution
Consider code that receives UTF-8 data from an external source:
raw_name = b"Marta"
name = raw_name.decode("utf-8")
greeting = "Hello, " + name
print(greeting)
Step by step:
b"Marta"creates abytesobject. Its contents are the byte values for the ASCII/UTF-8 letters inMarta.raw_name.decode("utf-8")interprets those bytes using UTF-8 and returns thestrvalue"Marta"."Hello, "andnameare bothstrvalues, so Python can concatenate them.print()displays:
Hello, Marta
If you skip decoding, Python rejects the mixed types:
raw_name = b"Marta"
greeting = "Hello, " + raw_name # TypeError
This is intentional: Python requires you to decide how bytes should be interpreted as text.
Real World Use Cases
Use bytes when an API expects or returns raw data rather than Python text.
-
Reading binary files: Images, PDFs, ZIP archives, and executable data are bytes.
with open("photo.jpg", "rb") as file: image_data = file.read() -
Writing binary files: A program may generate a binary format.
with open("output.bin", "wb") as file: file.write(b"\x00\x01\x02") -
Network communication: Sockets send and receive bytes.
request = "PING\r\n".encode("utf-8") -
Web requests and API responses: HTTP response bodies are often received as bytes before being decoded as text or parsed as JSON.
-
Cryptography and hashing: Hash functions operate on bytes.
import hashlib digest = hashlib.sha256(b"important data").hexdigest() -
Binary protocols: Hardware devices and custom protocols may specify exact byte values, such as
b"\xaa\x01\x00".
Real Codebase Usage
In real projects, developers usually avoid scattering b literals throughout application logic. Instead, they keep text as str and convert only at system boundaries.
Encode before sending or storing
def send_message(socket, message: str) -> None:
socket.sendall(message.encode("utf-8"))
Decode as soon as received
def read_message(socket) -> str:
response = socket.recv(4096)
return response.decode("utf-8")
This approach keeps most business logic working with readable Unicode text.
Use byte literals for fixed protocol markers
PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n"
with open("image.png", "rb") as file:
if file.read(8) != PNG_SIGNATURE:
raise ValueError("Not a PNG file")
Validate before decoding untrusted data
External bytes may not be valid in the expected encoding:
try:
text = incoming_data.decode("utf-8")
except UnicodeDecodeError:
text = ""
The correct error-handling policy depends on the application. Some programs reject invalid input; others log it or use a documented fallback.
Common Mistakes
Mixing str and bytes
Python does not automatically combine text and bytes:
# Broken
label = "User: " + b"Marta"
Fix it by decoding the bytes or encoding the text:
label = "User: " + b"Marta".decode("utf-8")
# or, when bytes are required:
label_bytes = b"User: " + "Marta".encode("utf-8")
Assuming b means “binary text”
b"hello" is a bytes object, not a special version of text. Use a regular str unless an API specifically needs bytes.
Writing non-ASCII characters directly in a bytes literal
This is invalid:
# Broken: bytes literals may directly contain ASCII characters only
word = b"café"
Encode a text string instead:
word = "café".encode("utf-8")
Decoding with the wrong encoding
data = "café".encode("utf-8")
# data.decode("ascii") # UnicodeDecodeError
Use the encoding that was used to create the data. If you control both sides, UTF-8 is a common choice.
Forgetting binary file mode
Use "rb" and "wb" for raw files. Text modes ("r" and "w") read or write str and handle encoding for you.
Expecting byte indexing to return a one-character bytes object
value = b"ABC"[0]
print(value) # 65, not b'A'
To get a one-byte slice, use:
first_byte = b"ABC"[0:1] # b'A'
Comparisons
| Feature | str | bytes |
|---|---|---|
| Literal example | "hello" | b"hello" |
| Represents | Unicode text characters | Raw values from 0 to 255 |
| Typical use | Names, messages, JSON text | Files, sockets, hashes, protocols |
| Iteration result | One-character str values | Integers |
| Convert from the other type | data.decode("utf-8") | text.encode("utf-8") |
| Direct non-ASCII literal content | Allowed | Not allowed; encode a str instead |
String literal prefixes
| Prefix | Meaning | Example |
|---|---|---|
b | Create bytes | b"OK" |
r | Treat backslashes as mostly literal characters | r"C:\\temp\\file.txt" |
f | Format expressions inside {} | f"Hello, {name}" |
u | Unicode string prefix; accepted mainly for compatibility in modern Python | u"hello" |
rb or br | Raw bytes literal | rb"\x41" |
rf or fr | Raw formatted string | rf"{folder}\\file.txt" |
Not every prefix combination is valid. In particular, bytes literals cannot be f-strings: bf"..." is invalid. Build text with an f-string and then call .encode() if bytes are needed.
Cheat Sheet
# Text
text = "hello" # str
# Bytes
raw = b"hello" # bytes
# Text -> bytes
raw = text.encode("utf-8")
# Bytes -> text
text = raw.decode("utf-8")
# Binary file operations
open("file.dat", "rb") # read bytes
open("file.dat", "wb") # write bytes
# Exact byte values
marker = b"\x00\xff"
- Use
strfor human-readable text. - Use
bytesfor raw data and APIs that require bytes. - Do not concatenate or compare text and bytes as though they are the same type.
- Specify an encoding when converting; UTF-8 is commonly used.
bytes[index]returns an integer;bytes[start:end]returnsbytes.- A
bliteral may directly contain ASCII characters. Encode a normal string for non-ASCII text.
FAQ
What does b mean before a string in Python?
It creates a bytes object instead of a normal str object. For example, b"abc" is byte data, while "abc" is Unicode text.
Is b"hello" the same as "hello"?
No. They may look similar when printed, but they have different types and cannot be freely mixed. b"hello" is bytes; "hello" is str.
When should I use a bytes literal in Python?
Use one for fixed raw data, such as file signatures, protocol commands, byte markers, and test fixtures. For ordinary user-facing text, use str.
How do I convert a Python string to bytes?
Call encode() with an encoding:
payload = "Hello".encode("utf-8")
How do I convert bytes to a Python string?
Call decode() with the encoding used for the data:
text = b"Hello".decode("utf-8")
Why does Python show b'...' when printing bytes?
The b in the displayed representation distinguishes byte data from a text string. It is not an extra byte inside the data.
What does the u prefix mean in Python 3?
Python 3 strings are Unicode by default, so u"text" behaves like "text". The prefix remains accepted mainly for compatibility with older code.
Can a bytes literal contain emoji or accented characters?
Not directly. Start with a normal Unicode string and encode it, for example: "🚀".encode("utf-8").
Mini Project
Description
Build a small packet creator and reader. The packet has a fixed byte marker followed by a UTF-8 encoded message. This mirrors how programs mix raw protocol bytes with human-readable text in files and network messages.
Goal
Create a byte packet from a text message, then validate and decode the packet back into text.
Requirements
- Define a bytes constant that identifies the start of a packet.
- Create a function that accepts a
strmessage and returns abytespacket. - Create a function that validates the packet marker.
- Decode the message portion as UTF-8.
- Raise
ValueErrorwhen the packet does not have the expected marker.
Keep learning
Related questions
@staticmethod vs @classmethod in Python Explained
Learn the difference between @staticmethod and @classmethod in Python with clear examples, use cases, mistakes, and a mini project.
Add Rows to a Pandas DataFrame in Python
Learn how to add rows to a Pandas DataFrame, why repeated row appends are slow, and when to use loc, concat, or record lists.
Call a Function by Name in a Python Module
Learn how to call a function by name in a Python module using strings, getattr, and safe patterns for dynamic function dispatch.