What is the difference between str and bytes?

A str is a sequence of code points and carries no encoding. bytes is a sequence of 8-bit values and carries no meaning until you name one. encode goes str → bytes, decode comes back, and the rule is to do both at the edges of your program and work in str everywhere inside.

Overview

Two different things that both print nicely

"hi" and b"hi" look almost identical and are not comparable: "hi" == b"hi" is False, and in Python 3 that is deliberate. A str has no encoding — asking for the bytes of a str is meaningless until you say which bytes, which is why encode takes an argument.

Indexing differs too. s[0] on a str gives a one-character str; b[0] on bytes gives an int. That catches people constantly.

StringsConceptualMedium

Step through it

What to watch

  • One code point became two bytes — positions stop matching.
  • Slicing bytes can split a character in half; slicing str cannot.
  • The boundary is always I/O: files, sockets, subprocesses.

Say this out loud

"str is text, bytes is data. Encode at the way out, decode at the way in, and never let bytes travel through your logic."

What is the difference between str and bytes?

What is the difference between str and bytes, and when do you need encode and decode?

The sandwich rule

Decode at the boundary in, encode at the boundary out, and keep the middle in str. Every layer of a well-behaved program works in text; only the outermost layer knows about UTF-8.

Violating it produces the two classic errors. UnicodeDecodeError means you were handed bytes that are not valid in the encoding you claimed — usually the encoding is wrong, not the data. UnicodeEncodeError means you tried to write a character the target encoding cannot represent, which is what happens when something defaults to ASCII or latin-1.

Where it actually shows up

Reading a file with open(path) gives str and applies your platform's default encoding, which differs between machines and is the source of "works on my laptop" bugs. Pass encoding="utf-8" explicitly, always. open(path, "rb") gives bytes and does not guess.

Sockets, subprocess output, hashlib and most binary formats are bytes. hashlib.sha256(s) is a TypeError until you encode — a hash is defined over bytes, so the encoding is part of the answer.

Run it in Python

The same text as both types, with the ways they refuse to mix, and both Unicode errors triggered on purpose so you have seen the tracebacks before an interviewer describes one.

str_bytes.pyPython 3
Output

How the code works

  1. s.encode("utf-8")The encoding is an argument because a str genuinely does not have bytes until you choose. There is no default worth relying on.
  2. b[1] is an intIndexing bytes yields the numeric value, not a one-length bytes. It is the single most common surprise when code written for str is pointed at bytes.
  3. b[:2].decode("utf-8")Raises, because the slice split a two-byte character. Any code that chunks a byte stream has to respect character boundaries, which is why streaming decoders exist.
  4. b.decode("latin-1")The dangerous one: no exception, wrong text. latin-1 maps every byte to something, so it never fails and never warns. Mojibake is this, not a corrupted file.

Change one thing

  • Encode as utf-16 and print the bytes. Note the byte-order mark at the front, and that the length roughly doubles.
  • Call b.decode("utf-8", errors="replace") on the broken slice. You get U+FFFD instead of an exception — useful for logs, wrong for data you intend to keep.

Where this runs

Real CPython, compiled to WebAssembly and running on your own machine — nothing is uploaded. The first run takes a few seconds while the interpreter downloads; after that it is immediate. Need more room, or want to paste your own attempt? Use the Python compiler.

Check yourself

0 of 3

Answer without scrolling back up.

  1. b[0] where b is a bytes object gives you:

  2. Decoding UTF-8 data as latin-1 produces:

  3. Where should encode and decode happen in a well-structured program?

Cheat sheet

What is the difference between str and bytes?

A str is a sequence of code points and carries no encoding. bytes is a sequence of 8-bit values and carries no meaning until you name one. encode goes str → bytes, decode comes back, and the rule is to do both at the edges of your program and work in str everywhere inside.

INTERVIEW · vizlearn.in/interview/str-versus-bytes-in-python.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.