Question
Convert Strings to Bytes in Python 3: encode() vs bytes()
Question
In Python 3, converting a string to bytes can be done in either of these ways:
copy_b = bytes(my_string, "utf-8")
b = my_string.encode("utf-8")
Both approaches can address errors such as TypeError: 'str' does not support the buffer interface. What is the difference between bytes(my_string, "utf-8") and my_string.encode("utf-8")? Which approach should be preferred, and why?
Short Answer
Python 3 keeps text (str) and binary data (bytes) separate. You will learn how encoding converts text into bytes, why an encoding such as UTF-8 is required, and when str.encode() or the bytes() constructor is the clearest choice.
Concept
In Python 3, a str is text: a sequence of Unicode characters. A bytes object is binary data: a sequence of integer values from 0 to 255.
For example, the visible text "café" is a str. To write it to a network socket, save it in a binary file, or pass it to an API that expects raw bytes, Python must convert the characters into a byte sequence. This conversion is called encoding.
text = "café"
data = text.encode("utf-8")
print(text) # café
print(data) # b'caf\xc3\xa9'
print(type(data)) # <class 'bytes'>
UTF-8 is the usual choice because it can represent every Unicode character and is the standard encoding for web content, JSON, many APIs, and modern text files.
For an ordinary string, these expressions produce the same bytes:
text.encode("utf-8")
bytes(text, "utf-8")
str.encode() communicates the operation more directly: you are asking a string to encode itself. The constructor is more general because it can create bytes from other source types as well, such as integers, iterables of byte values, and existing byte-like objects.
Mental Model
Think of a str as a message written in human-readable characters and bytes as the sealed package used to transport that message through a computer system.
An encoding is the packing rule. UTF-8 tells Python exactly how to turn each character into one or more byte values.
text.encode("utf-8")means: “Pack this text using UTF-8.”bytes(text, "utf-8")means: “Construct a bytes package from this text using UTF-8.”
Both can create the same package, but encode() makes the text-to-bytes intent easier to recognize.
Syntax and Examples
Use encode() when you have text and need bytes.
text = "Hello, world!"
data = text.encode("utf-8")
print(data) # b'Hello, world!'
print(type(data)) # <class 'bytes'>
The equivalent bytes() form is:
text = "Hello, world!"
data = bytes(text, "utf-8")
print(data) # b'Hello, world!'
Both APIs also support an error-handling strategy:
text = "Price: €20"
utf8_data = text.encode("utf-8")
ascii_data = text.encode("ascii", errors="replace")
print(utf8_data) # b'Price: \xe2\x82\xac20'
print(ascii_data) # b'Price: ?20'
Common encoding choices:
"utf-8": default choice for most modern applications."ascii": only supports basic English characters and control characters.
Step by Step Execution
Consider this example:
message = "Hi €"
payload = message.encode("utf-8")
restored = payload.decode("utf-8")
print(payload)
print(restored)
Execution trace:
messagecontains Unicode text:"Hi €".message.encode("utf-8")converts each character to UTF-8 bytes:Hbecomes0x48ibecomes0x69- the space becomes
0x20 €becomes three bytes:0xE2 0x82 0xAC
payloadis nowb'Hi \xe2\x82\xac', which has typebytes.payload.decode("utf-8")reads those bytes using the same UTF-8 rule and reconstructs the originalstr.- The first shows the byte representation; the second prints the human-readable text:
Real World Use Cases
Text-to-bytes conversion is needed whenever text crosses a binary boundary.
-
HTTP requests: send a text request body as UTF-8 bytes.
body = "name=Ada".encode("utf-8") -
Network sockets:
socket.sendall()expects bytes-like data.client_socket.sendall("PING\n".encode("utf-8")) -
Binary files: files opened with
"wb"expect bytes.with open("message.bin", "wb") as file: file.write("Saved data".encode("utf-8")) -
Cryptographic hashes: hashing functions operate on bytes, not text.
import hashlib digest = hashlib.sha256("secret".encode("utf-8")).hexdigest() -
Database or external APIs: some drivers and SDKs require bytes for protocol payloads, signatures, or uploaded content.
Real Codebase Usage
In production code, developers usually make conversion boundaries explicit.
Prefer encode() when a value is known to be text
json_text = '{"active": true}'
body = json_text.encode("utf-8")
This reads naturally and makes code review easier: json_text is text, and body is bytes.
Validate input types at API boundaries
A function that accepts either text or bytes can normalize its input once:
def to_utf8_bytes(value: str | bytes) -> bytes:
if isinstance(value, bytes):
return value
if isinstance(value, str):
return value.encode("utf-8")
raise TypeError("value must be str or bytes")
This is useful for logging libraries, messaging clients, and utility functions.
Use explicit encodings for external data
(, , encoding=) file:
report = file.read()
Common Mistakes
Concatenating text and bytes
This is invalid because the types represent different kinds of data:
name = "Ada"
message = b"Hello, " + name # TypeError
Encode the text first:
message = b"Hello, " + name.encode("utf-8")
Or keep the entire operation as text until the final boundary:
message = f"Hello, {name}".encode("utf-8")
Calling bytes() on a string without an encoding
This fails:
bytes("hello") # TypeError
Python needs to know the encoding rule for converting characters to bytes:
bytes("hello", "utf-8")
Assuming bytes are readable text
data = "café".encode()
(data)
Comparisons
| Operation | Input | Output | Typical use |
|---|---|---|---|
text.encode("utf-8") | str | bytes | Preferred, clear text-to-bytes conversion |
bytes(text, "utf-8") | str plus encoding | bytes | Equivalent for strings; useful when constructor style fits surrounding code |
data.decode("utf-8") | bytes | str | Convert received or stored bytes into text |
str(data) |
Cheat Sheet
# Text -> bytes (recommended for known strings)
data = text.encode("utf-8")
# Equivalent text -> bytes constructor form
# Encoding is required when the source is str.
data = bytes(text, "utf-8")
# Bytes -> text
a_text = data.decode("utf-8")
stris Unicode text.bytesis binary data.- Use UTF-8 unless an external format requires another encoding.
encode()convertsstrtobytes.decode()convertsbytestostr.- Do not concatenate
strandbytesdirectly. - Use the same encoding for decoding that was used for encoding.
- For files, specify
encoding="utf-8"in text mode rather than encoding manually. bytes("text")fails because Python needs an encoding.str(b"text")does not decode the bytes; use.decode()instead.
FAQ
Are str.encode() and bytes(string, encoding) the same in Python?
For an ordinary string and the same encoding and error-handling setting, they produce the same byte sequence. str.encode() is generally preferred because it clearly expresses text encoding.
Which encoding should I use to convert a Python string to bytes?
Use UTF-8 unless the protocol, file format, API, or legacy system explicitly requires another encoding.
Why does bytes("hello") raise a TypeError?
A string contains characters, and Python needs an encoding rule to turn those characters into byte values. Use bytes("hello", "utf-8") or "hello".encode("utf-8").
How do I convert bytes back to a string in Python 3?
Call decode() with the correct encoding:
text = data.decode("utf-8")
Does UTF-8 use one byte per character?
Not always. Basic ASCII characters use one byte, while many characters use two, three, or four bytes in UTF-8.
When should I use errors="replace" or errors="ignore"?
Use them only when data loss or replacement is acceptable, such as displaying imperfect external data. For important data, let the error occur or handle it explicitly so encoding problems are not hidden.
Mini Project
Description
Build a small message-packet utility for a network-style boundary. It converts user text into UTF-8 bytes before sending and converts received bytes back into text. The project demonstrates keeping text and binary data separate.
Goal
Create functions that safely encode text messages as UTF-8 bytes and decode UTF-8 byte packets back to text.
Requirements
Accept a str message and return UTF-8 bytes.
Reject values that are not strings when encoding.
Accept a bytes packet and return decoded UTF-8 text.
Reject values that are not bytes when decoding.
Demonstrate a round trip containing a non-ASCII character.
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.