PythonMastery
reference 3 min read · lesson 50 of 60 in Errors

TypeError: object of type 'int' has no len()

1 · The lesson

read

What this error means

len() asks an object how many items it holds. Strings, lists, tuples, dicts, sets and ranges know the answer. A number doesn't hold items, so it has no length — and neither does None, or a generator that hasn't produced its items yet.

The type in quotes tells you what you actually passed. 'int' and 'float' mean a number; 'NoneType' means a missing value; 'generator', 'map', 'filter' or 'zip' mean a lazy iterator.

When you see it

python
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    if len(pin) != 4:
       ~~~^^^^^
TypeError: object of type 'int' has no len()
python
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    print(len(paid))
          ~~~^^^^^^
TypeError: object of type 'generator' has no len()

Why it happens

Either the value isn't the type you think it is, or it is a type that can't know its length up front.

  • A number where you expected a string. int(input()), a JSON field like "pin": 4821, or a pandas column of IDs read as integers. len(4821) is meaningless to Python, even though you can see four digits.
  • None where you expected a list. A function that forgot to return, or a lookup that found nothing.
  • A generator or iterator. map(), filter(), zip(), enumerate() and generator expressions produce items one at a time. They don't know how many are left until they've run out, so they don't pretend to.
python
orders = [{"id": "A1", "paid": True}, {"id": "A2", "paid": False}, {"id": "A3", "paid": True}]
paid = (o for o in orders if o["paid"])
print(len(paid))     # TypeError: object of type 'generator' has no len()

How to fix it

To count the digits of an integer, convert it to a string first — and drop the minus sign, or it counts as a character:

python
pin = 4821
print(len(str(pin)))            # 4

balance = -1250
print(len(str(balance)))        # 5 — the '-' counts
print(len(str(abs(balance))))   # 4

If the value is a code that must keep its leading zeros — a PIN, a postcode, a phone number — it was never a number. Keep it as a string from the start; int("0042") is 42, and the zeros are gone for good.

To count a generator, either consume it or build a list. Pick based on whether you need the items again:

python
orders = [{"id": "A1", "paid": True}, {"id": "A2", "paid": False}, {"id": "A3", "paid": True}]

# Only need the count: count as you go, no list kept in memory
print(sum(1 for o in orders if o["paid"]))        # 2

# Need the count AND the items: make a list once
paid = [o for o in orders if o["paid"]]
print(len(paid), [o["id"] for o in paid])         # 2 ['A1', 'A3']

Counting a generator uses it up. If you count it with sum(1 for _ in gen) and then loop over gen, the loop runs zero times — silently.

For map() or filter(), wrap it in list():

python
names = map(str.title, ["ada", "grace", "linus"])
names = list(names)
print(len(names), names)        # 3 ['Ada', 'Grace', 'Linus']

For None, find out why the value is missing. If an empty result is legitimate, have the function return [] instead of None, and len() gives 0 with no special case.

When you'd actually see this in real code

  • Validating a PIN or OTP that was converted with int() before the length check. Check the length on the string, then convert.
  • Reading IDs from a CSV with pandas, which turns "00731" into the integer 731. Pass dtype={"customer_id": str} to read_csv.
  • Porting Python 2 code, where map() and filter() returned lists and len(map(...)) worked.
  • len(re.finditer(...)) — finditer is lazy ('callable_iterator' in the message). Use re.findall if you only need a count.
  • Calling len() on the result of dict.get() when the key is missing ('NoneType').

See Also

Found this useful? Share it with a friend who’s learning Python.