Neither is better than the other, they do exactly the same thing. However, using .encode() and .decode() is the more common way to do it. It is also compatible with Python 2.

Answer from Lennart Regebro on Stack Overflow
Top answer
1 of 3
74

Neither is better than the other, they do exactly the same thing. However, using .encode() and .decode() is the more common way to do it. It is also compatible with Python 2.

2 of 3
19

To add to Lennart Regebro's answer There is even the third way that can be used:

encoded3 = str.encode(original, 'utf-8')
print(encoded3)

Anyway, it is actually exactly the same as the first approach. It may also look that the second way is a syntactic sugar for the third approach.


A programming language is a means to express abstract ideas formally, to be executed by the machine. A programming language is considered good if it contains constructs that one needs. Python is a hybrid language -- i.e. more natural and more versatile than pure OO or pure procedural languages. Sometimes functions are more appropriate than the object methods, sometimes the reverse is true. It depends on mental picture of the solved problem.

Anyway, the feature mentioned in the question is probably a by-product of the language implementation/design. In my opinion, this is a nice example that show the alternative thinking about technically the same thing.

In other words, calling an object method means thinking in terms "let the object gives me the wanted result". Calling a function as the alternative means "let the outer code processes the passed argument and extracts the wanted value".

The first approach emphasizes the ability of the object to do the task on its own, the second approach emphasizes the ability of an separate algoritm to extract the data. Sometimes, the separate code may be that much special that it is not wise to add it as a general method to the class of the object.

🌐
The Python Coding Stack
thepythoncodingstack.com › the python coding stack › `bytes`: the lesser-known python built-in sequence • and understanding utf-8 encoding
`bytes`: The Lesser-Known Python Built-In Sequence • And Understanding UTF-8 Encoding
July 15, 2025 - You can get a free trial at The Python Coding Place and you also get access to a members-only forum. ... So, back to 1's and 0's. The accented letter é is represented by two bytes. The value of the first of these bytes is c3 in hexadecimal, which is 195 in decimal. Let's convert this to binary: ... Here's how to understand a byte in a UTF-8 encoded number.
🌐
Educative
educative.io › answers › what-is-bytesdecode-in-python
What is bytes.decode() in Python?
Let’s look at an example to see how the bytes.decode() method works. ... Line 3: We encode string, cast to byte object.
🌐
DataCamp
datacamp.com › tutorial › string-to-bytes-conversion
How to Convert String to Bytes in Python | DataCamp
June 5, 2024 - In Python, use the .encode() method on a string to convert it into bytes, optionally specifying the desired encoding (UTF-8 by default).
🌐
freeCodeCamp
freecodecamp.org › news › python-bytes-to-string-how-to-convert-a-bytestring
Python Bytes to String – How to Convert a Bytestring
April 10, 2023 - In this example, we define a byte string b"Hello, world!" and use the str() constructor to convert it to a string object. We specify the encoding format as utf-8 using the encoding parameter. Finally, we print the resulting string to the console. We can also use the bytes() constructor, a built-in Python function used to create a new bytes object.
🌐
Real Python
realpython.com › python-bytes
Bytes Objects: Handling Binary Data in Python – Real Python
March 5, 2025 - Python only understands unsigned bytes, but there are ways to emulate signed bytes should you need to—more on that later. Note: You could theoretically represent a floating-point number on a single byte by encoding the sign, exponent, and mantissa using fewer bits.
🌐
Programiz
programiz.com › python-programming › methods › built-in › bytes
Python bytes()
# convert string to bytes byte_message = bytes(message, 'utf-8') print(byte_message) # Output: b'Python is fun' ... bytes() method returns a bytes object which is an immutable (cannot be modified) sequence of integers in the range 0 <=x < 256. If you want to use the mutable version, use the ...
Find elsewhere
🌐
Python
docs.python.org › 3 › builtins › stdtypes.html
Built-in Types — Python 3.14.7 documentation
>>> encoded_str_to_bytes = 'Python'.encode() >>> type(encoded_str_to_bytes) <class 'bytes'> >>> encoded_str_to_bytes b'Python'
🌐
DigitalOcean
digitalocean.com › community › tutorials › python-string-encode-decode
Python String Encode and Decode: Complete Guide | DigitalOcean
Master Python string encode() and decode() methods. Learn UTF-8, ASCII, Unicode handling, error handling modes, and practical encoding/decoding examples.
🌐
Python documentation
docs.python.org › 3 › howto › unicode.html
Unicode HOWTO — Python 3.14.7 documentation
UTF stands for “Unicode Transformation Format”, and the ‘8’ means that 8-bit values are used in the encoding. (There are also UTF-16 and UTF-32 encodings, but they are less frequently used than UTF-8.) UTF-8 uses the following rules: If the code point is < 128, it’s represented by the corresponding byte value.
🌐
Real Python
realpython.com › convert-python-bytes-to-strings
How to Convert Bytes to Strings in Python – Real Python
July 18, 2026 - If you try decoding a bytes object with a different encoding from what was used to encode it, then you’ll end up with garbled data. It’s like using a French dictionary to translate Russian. You’re bound to meet some very confused Russians. If no encoding is specified, Python defaults to UTF-8, which is the standard encoding for almost all modern systems and web data.
🌐
DataCamp
datacamp.com › tutorial › bytes-to-string-python
How to Convert Bytes to String in Python | DataCamp
June 12, 2024 - To convert bytes to strings in Python, we can use the .decode() method, specifying the appropriate encoding.
🌐
Medium
medium.com › @vivekmcm1 › understanding-pythons-encode-and-decode-with-real-world-examples-5d2080d66f01
Understanding Python’s encode() and decode() with Real-World Examples | by Vivek | Medium
August 30, 2025 - errors tells Python what to do if it encounters a character that can’t be encoded (strict, ignore, replace). ... text = "Hello World" byte_text = text.encode() # Default UTF-8 encoding print(byte_text) # b'Hello World'
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-convert-string-to-bytes
Convert String to bytes-Python - GeeksforGeeks
It turns a string into a sequence of bytes using a specified encoding format (default is UTF-8).
Published: July 11, 2025
🌐
Sentry
sentry.io › sentry answers › python › convert a string to bytes in python
Convert a String to Bytes in Python with encode() | Sentry
July 15, 2023 - Use the str.encode() method or the bytes() constructor to convert a Python string into a bytes object, with UTF-8 as the default character encoding
🌐
Reddit
reddit.com › r/learnpython › why is encoding bytes to utf-8 called decoding?
r/learnpython on Reddit: Why is encoding bytes to UTF-8 called decoding?
March 30, 2022 -

This always confuses me every single time. I remember it by doing the opposite of what I intuitively think it should be. Perhaps I'm the only one?

bytes.decode - encodes the bytes as UTF-8

str.encode - decodes "removes" the UTF-8 encoding

There is also the abbreviation BADTIE: Bytes Are Decoded, Text Is Encoded. To help to remember it.

Top answer
1 of 4
25
You are indeed confused: bytes.decode - encodes the bytes as UTF-8 No, it decodes a byte sequence to a string, interpreting it as an UTF-8 encoded string. Strings are a sequence of code points (or characters) in Unicode. Unicode and UTF-8 are not the same thing! UTF-8 is the most popular, but still only one of many encoding schemes for Unicode. Take the string ABCÄĀ. This is represented by the unicode code point sequence U+0041 U+0042 U+0043 U+00c4 U+0100. As you see, unicode code points are more than 8 bits, so we need a way to store them in 8-bit byte sequences. One way to do that is to use UTF-8, which turns it into the byte sequence 0x41 0x42 0x43 0xc3 0x84 0xc4 0x80. As another example, UTF-16 would encode this as 0xff 0xfe 0x00 0x41 0x00 0x42 0x00 0x43 0x00 0xc4 0x01 0x00. Notice that except for the 0xff 0xfe BOM (Byte Order Mark) at the beginning, it's simply storing the 16 bit value of the code point in sequence (code points can have more than 16 bits, so it only works this way below 32768, similar to how UTF-8 doesn't change the representation below 128). The BOM is needed to know which of the two bytes represents the most significant bits, as in, is 0x12 0x34 representing 0x1234 or 0x3412. (Some machines store 16 bit values in the first way ("big endian"), others, like x86, in the other ("little endian")) There are also other encoding schemes, for example, if every unicode code point is below 256, you can use latin-1, which will just use the lower 8 bits of the unicode code point. To summarize: bytes.decode decodes a byte sequence into a string, which is an abstract representation of code points. str.encode turns this abstract representation into a byte sequence.
2 of 4
11
Because in Python 3 the strings are in unicode by default, and bytes are an optional encoding, if you want to deal with things on that level.
🌐
Net Informations
net-informations.com › python › iq › byte.htm
How to convert bytes to string in Python?
When you convert a bytes object ... or "stringifying" the bytes object. In Python, the default encoding used for decoding bytes objects to strings is UTF-8....
Top answer
1 of 1
2

bytes

You are working with bytes which is very cumbersome.

  • You have to prefix all literals
  • single bytes have type int and need to be converted to to bytes again At least I cannot do this without debugging some errors.

It is much more convenient to work with strings. So I suggest to decode the bytes to a string with an 8-bit codec like 'latin-1'. No more bytes([x]) or x.to_bytes(). You can use plain comprehension, plain ''.join(), etc. If required you encode the string to bytes again with the very same codec.

dict.get()

For conditional translations there is a nice trick - dict.get() - which allows to pass a default value for non-existing keys.

translated = replacements.get(char, char)

This returns replacements[char] if char is in replacements.keys(). Otherwise it returns the default char. To use this functionality you include the escape character in the translation table (however you fill it).

replacements = {escape_char: escape_char + escape_char,
       '\n':   escape_char + '\x00',
       '\xfd': escape_char + '\x01',
       '\xfe': escape_char + '\x02',
       '\xff': escape_char + '\x03',
       }

The encoding function now reads

def encode(data: bytes) -> bytes:
    str_data = data.decode(encoding='latin-1')
    str_enc = ''.join(replacements.get(x, x) for x in str_data)
    return str_enc.encode(encoding='latin-1')

loop like a pro

In your decoding function you loop over len(data) which is an anti-pattern. You should always loop over the elements. To make it worse you use a while loop and increment the loop counter manually. You also access elements with index i+1 which again is error prone. Loop over elements only and keep a little state like a previous_byte. You cannot be out of bounds.

def decode(data: bytes) -> bytes:
    d_data = data.decode(encoding='latin-1')
    l = []
    esc = ''
    for x in d_data:
        if not esc and x == escape_char:
            esc = x
            continue
        l.append(reverse_replacements.get(esc + x, esc + x))
        esc = ''
    assert esc == ''
    return ''.join(l).encode(encoding='latin-1)')

testing

For your nicely testable functions you should provide some tests. There are unit test frameworks available. You can also do the most primitive assertions, of course in a main guard.

if __name__ == '__main__':
    assert encode(b"asdf") == b"asdf"
    assert decode(b"asdf") == b"asdf"

    assert encode(b"as\ndf") == b"as=\x00df"
    assert decode(b"as=\x00df") == b"as\ndf"
    assert encode(b"\ndf") == b"=\x00df"
    assert decode(b"=\x00df") == b"\ndf"
    assert encode(b"as\n") == b"as=\x00"
    assert decode(b"as=\x00") == b"as\n"

    assert encode(b"as\xfddf") == b"as=\x01df"
    assert decode(b"as=\x01df") == b"as\xfddf"

    assert encode(b"as\xfedf") == b"as=\x02df"
    assert decode(b"as=\x02df") == b"as\xfedf"

    assert encode(b"as\xffdf") == b"as=\x03df"
    assert decode(b"as=\x03df") == b"as\xffdf"