TypeError Object Is Not Subscriptable in Python

Python throws TypeError <object> is not subscriptable if you attempt to access a value in an object which is not indexable using the indexer operator ([ ]).

An indexable/ subscriptable object contains the __getitem__() magic/dunder function, which allows the object to act as a container of some elements.

In python, indexable objects include lists, tuples, strings, and arrays, whereas sets, None, numeric values (integers and floats), and dictionary values are not.

# This is a list. It is an indexable object in Python
list1 = [1, 2, "John", "Smith", 5, 6, 7, None]
# indexing using indexer operator, []
print(list1[2])
# Indexing using the dunder function, __getitem__()
print(list1.__getitem__(2))

Output:

John
John

As shown in the output, the indexer operator ([ ]) calls the dunder function __getitem__() in the background, which is why both ways of indexing yield the same result.

Reproducing TypeError: Object Is Not Subscriptable

This error arises when we try to index an object which is not subscriptable. Here are some examples.

num1 = 568
print(num1[0])

Output:

TypeError: 'int' object is not subscriptable
set1 = {1, "Simon", 345, 345, -7}
# set1 is printed in an unordered manner (sets are unordered)
# duplicates on set1 are removed on printing (sets hold unique items)
print(set1)
print(set1[0])

Output:

{345, 'Simon', -7, 1}
TypeError: 'set' object is not subscriptable

So far, we have seen that integers and sets are not subscriptable; therefore, trying to index them leads to an error.

Integers are not container objects and, therefore, not indexable. On the other, Python set is an unordered collection of unique elements. The unordered nature of Python sets makes them inherently non-subscriptable.

You can use the dir() function to check attributes supported by a given object. For example, dir(num1) and dir(set1) will show you that they don’t support the magic function __getitem__().

dict1 = {
	"Name": "Smith",
	"Major": "Biology",
	"Year": 2
}
# get dict1 values into dict_values object
dict1_values = dict1.values()
print(dict1_values)
print(dict1_values[0])#Error

Output:

dict_values(['Smith', 'Biology', 2])
TypeError: 'dict_values' object is not subscriptable

The operator, [ ], in the Python dictionary is used to access dictionary values using corresponding keys. For example, dict1[“name”] will yield “Smith” in the code above.

Just like integers and sets, dictionary values are not indexable. The dict_values object is a set-like object and uses a hash table to store its items, which is unsuitable for indexing.

This explanation holds in Python3 only. Dictionary values are indexable in Python 2; therefore, the code above will not yield an error in Python 2.

The Solution to TypeError: Object Is Not Subscriptable

Depending on the nature of this error, there are three solutions. Let’s discuss them as we give examples.

The first solution to this error is to ensure you are not indexing a non-subscriptable object. Secondly, you can cast non-indexable Python objects into indexable forms.

For example, in the case of dict_values, we can convert it into a list and index it accordingly. The same applies to Python sets – they can be converted to a list and then accessed items by index.

dict1 = {
	"Name": "Smith",
	"Major": "Biology",
	"Year": 2
}
# get dict1 values into dict_values object
dict1_values = dict1.values()
print(dict1_values)
# cast dict_values into a list - indexable
list1d = list(dict1_values)
print(list1d[0])

Output:

dict_values(['Smith', 'Biology', 2])
Smith
set1 = {1, "Simon", 345, 345, -7}
# convert set1 into a list
list1s = list(set1)
print(list1s)
# access the first element of the list
print(list1s[0])

Output:

[345, -7, 1, ‘Simon’]

345

Note: Be careful when indexing sets converted into a list because they may not yield the expected results. Python sets are unordered. They do not preserve the order when cast into another data type ( even when printed).

Another solution is to create the __getitem__() magic function on the object you want to make it subscriptable, if possible. For example, consider the following Persons() class.

class Persons():
	def __init__(self, names):
    	self.names=names
# Initialize object instance
p1=Persons(["Alice", "Bob", "Smith"])
# attempt to index the class object. Leads to error.
print(p1[1])

Output:

TypeError: 'Persons' object is not subscriptable

Python class object is not indexable, and therefore we get the error. We can modify the class by adding the __getitem__() function, and the object will be indexable.

class Persons():
	def __init__(self, names):
    	self.names=names
	def __getitem__(self,index):
    	return self.names[index]
p1=Persons(["Alice", "Bob", "Smith"])
print(p1[1])

Output:
Bob

The use of __getitem__() in the class allowed us to use the indexer operator ([ ]) with the reference variables of the Persons class to access values of the “names” list.

When we try to access an element in p1 using p1[1], the p1.__getitem__() is automatically called. The dunder function takes the index as an argument and returns the name associated with the given index.

Conclusion

Python throws TypeError <object> is not subscriptable when we try to index an object which is not indexable.

In this article, we showed how and why this error occurs and covered three ways of solving this problem: avoid indexing non-subscriptable objects, cast non-indexable objects into indexable form, and lastly, create __getitem__() function and use it accordingly to enable indexing of otherwise non-subscriptable.