Fixing the “TypeError: ‘dict’ object is not subscriptable” Error in Python

The “TypeError: ‘dict’ object is not subscriptable” is a common Python error indicating you tried to access a dict object using list syntax. Dictionaries in Python are powerful data structures that behave differently than sequences like lists or tuples. By understanding dictionaries and this exception, you can efficiently troubleshoot and fix these kinds of errors in your code.

In this guide, you will learn:

  • The causes and mechanics of this TypeError for dictionaries
  • How to recreate and debug this exception using example code
  • Techniques to resolve it with proper handling of dict objects
  • When this error may indicate other logical bugs in your program
  • How to structure your code to avoid “dict is not subscriptable” entirely
  • Alternatives to dicts if list-like access is required for your use case

Follow along to master debugging and fixing the “TypeError: ‘dict’ object is not subscriptable” to improve your Python coding skills when working with Python dicts.

The TypeError Explained

The “TypeError: ‘dict’ object is not subscriptable” exception indicates you tried accessing a dict as if it were a list or tuple.

For example, this access is invalid:

my_dict = {'a': 1, 'b': 2}
print(my_dict[0]) # TypeError!

Dictionaries in Python are unordered mappings from keys to values. So the concept of accessing a dict at an integer index doesn’t make sense and will throw a TypeError.

Let’s examine the mechanics of this further.

Dictionaries vs Lists in Python

Dictionaries and lists are two of Python’s essential mutable data structures with some key differences:

  • Lists are ordered sequences accessed via integer indexes.
  • Dicts are unordered key-value mappings accessed by keys.

Lists support operations like:

values = ['a', 'b', 'c']
values[0] # 'a'
values[1] = 'd'

Whereas dicts map keys to values:

data = {'name': 'John', 'age': 40} 
data['name'] # 'John'
data['age'] = 41

Using list indexing to access a dict treats it as an ordered sequence when it is fundamentally a different type of object.

The Subscripting Operation

The reason this exception has “not subscriptable” in the name ties back to what subscripting means in Python.

Subscripting is the syntax in Python for accessing elements at a specific index like list[0] or array[2].

Trying to subscript a dict treats it as a sequenced object when it does not support integer indexing.

Understanding these basics helps grasp why this operation is invalid and results in a TypeError exception being raised.

Examples Causing This Exception

With some background on this TypeError, let’s walk through concrete examples that trigger it to gain experience spotting and debugging it.

Basic Invalid Subscript

The simplest case trying to access a dict by integer index:

>>> my_dict = {'a': 1, 'b': 2}
>>> my_dict[0] 
TypeError: 'dict' object is not subscriptable

This fails because my_dict is a dictionary that maps string keys to values. There is no ordering or 0th element concept.

For Loop Iteration

Another common mistake is trying to iterate through a dict like a list:

my_dict = {'a': 1, 'b': 2}

for i in range(len(my_dict)):
   print(my_dict[i]) # TypeError!

len() doesn’t apply to dicts so this raises an exception.

Calling methods incorrectly

Some list methods like .pop() also raise this exception if called on a dict:

my_dict = {'a': 1, 'b': 2}   
my_dict.pop(0) # TypeError!

Dict pop() only takes a key arg, not an index.

Initializing From Keys

Trying to initialize a dict from a sequence of values instead of keys also leads to errors down the line:

# Try to create dict from values
values = [1, 2, 3]
my_dict = dict(values) # {'1': 2, '3': 3} 

# Later attempt to index
my_dict[0] # KeyError!

The dict ends up with stringified keys which can’t be accessed as ints.

Unpacking Operator

Using the unpacking * operator on a dict tries to treat it as a list of arguments:

def print_args(*args):

my_dict = {'a': 1, 'b': 2} 

print_args(*my_dict) # TypeError!

Un packing only works for actual sequences like lists/tuples.

These examples showcase common ways you might run into “dict is not subscriptable” errors in practice. Knowing how to spot anti-patterns like this helps diagnose debugging faster.

Fixing “TypeError: ‘dict’ object is not subscriptable”

Once you identify the problematic subscripting operation, there are some general ways to address the error:

Use Keys Instead of Indexes

The key is fixing the code to access dict elements by key rather than integer index:

my_dict = {'a': 1, 'b': 2}

# Fix: access by key 
print(my_dict['a']) # 1

Most cases will boil down to simply using the dict keys properly.

Iterate with .items()

When looping through a dict, use .items():

my_dict = {'a': 1, 'b': 2}

# Fix: iterate over items
for k, v in my_dict.items():
    print(k, v)

This constructs key-value tuples to iterate properly.

Use get() Method

To safely lookup with default, use .get():

my_dict = {'a': 1}

# Fix: use .get()
print(my_dict.get('b', 0)) # 0

my_dict.get('b') would return None which you may want to replace with a default.

Convert to List of Items

If you need list-like access, convert to a list of (key, value) tuples:

my_dict = {'a': 1, 'b': 2}

# Fix: convert to list
dict_list = list(my_dict.items()) 

# Now can index properly
print(dict_list[0]) # ('a', 1)

This enables integer indexing into the converted list.

Rethink Data Structure

For scenarios requiring both key and index lookup, a dict may not be appropriate. Consider alternatives like OrderedDict or a custom class instead.

By leveraging keys, iterating properly, and reconsidering the data structures used, you can avoid and fix “dict is not subscriptable” errors.

Debugging Techniques for Dict Issues

Debugging data structure issues like the “dict not subscriptable” error involves some general debugging tips:

  • Reproducing – Isolate a small reproducible case of the issue
  • Printing – Inspect types, keys, indices around the error
  • Simplifying – Reduce large data structures down to small demo cases
  • Console – Use the interactive console to quickly experiment
  • Rubber ducking – Walk through your code logic step-by-step

You can also utilize the Python debugger pdb to inspect local variables and step through execution flow.

Set a breakpoint before the line raising the exception:

import pdb; pdb.set_trace()

bad_access = my_dict[0] # Breakpoint here

Then run it to enter debug mode and introspect what’s going on.

Mastering core debugging practices like these for data issues will help you drastically reduce time spent troubleshooting and resolving not just TypeErrors but many classes of bugs.

Leave a Comment