Does len() count characters or bytes?

Neither, strictly. len(s) counts code points. For ASCII that happens to equal both the byte count and what a reader would call characters, which is why the distinction stays hidden until an accent or an emoji arrives.

Overview

Three different counts

There are three things you could mean by "length", and they coincide only for ASCII:

Code points — what len(s) returns. A Python 3 str is a sequence of code points, and indexing gives you one.

Byteslen(s.encode('utf-8')). Depends entirely on the encoding, which is why the encoding has to be named. This is the number that matters for a database column or a network frame.

Grapheme clusters — what a human counts. Python has no built-in for this; it needs a library.

StringsConceptualMedium

Step through it

What to watch

  • The second and third rows look the same and are not equal.
  • One is as a single code point, the other is e plus a combining mark.
  • Normalising is what makes the comparison behave.

Say this out loud

"len counts code points. Bytes is len(s.encode('utf-8')), and neither is what a user calls a character once you have combining accents or emoji."

Does len() count characters or bytes?

Is len(s) the number of characters or the number of bytes?

Where it goes wrong

Two strings that render identically can have different lengths and compare unequal, because é can be one code point or two (e plus a combining accent). Users produce both, depending on their keyboard and operating system.

The fix is normalisation: unicodedata.normalize('NFC', s) before comparing or storing. Any system that accepts names, usernames or search terms needs this, and most learn it from a bug report.

Emoji are the other reliable surprise. A family emoji or a skin-tone modifier is several code points joined by zero-width joiners, so len says 5 or 7 for something a user counts as one, and slicing it in half produces garbage.

The practical rule

Use len(s) for indexing and slicing your own text. Use len(s.encode('utf-8')) whenever a limit is a storage or transport limit. Normalise on input. And if you are truncating text for display — a preview, a tweet counter — know that code points are an approximation you may have to replace.

Run it in Python

The same visible text three ways, with all three counts printed for each. The two strings in the middle look identical in your browser and are not equal.

lengths.pyPython 3
Output

How the code works

  1. len(s)Counts code points, because a Python 3 str is a sequence of code points. Indexing returns one of them.
  2. len(s.encode('utf-8'))The byte count, and the only one that answers "will this fit in the column?". It depends on the encoding, which is why the encoding must be named rather than assumed.
  3. a == bFalse for two strings that render identically. Equality is over code points, and the two forms are different sequences of them.
  4. unicodedata.normalize("NFC", ...)Puts both into the same canonical form so they compare equal. Any system taking user-entered names or search terms needs this on the way in.

Change one thing

  • Add a family emoji. len reports 7 or more — it is several people joined by zero-width joiners.
  • Encode the emoji as utf-32-le and compare the byte counts. Fixed-width encodings make len and bytes agree again, at four bytes per code point.

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. len(s) on a Python 3 string counts:

  2. Two strings render identically but compare unequal. The most likely cause is:

  3. You need to enforce a 100-character database limit. You should measure:

Cheat sheet

Does len() count characters or bytes?

Neither, strictly. len(s) counts code points. For ASCII that happens to equal both the byte count and what a reader would call characters, which is why the distinction stays hidden until an accent or an emoji arrives.

INTERVIEW · vizlearn.in/interview/does-len-count-characters-or-bytes.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.