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.
1 2 3 4 5 6 |
# 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.
1 2 |
num1 = 568 print(num1[0]) |
Output:
TypeError: 'int' object is not subscriptable
1 2 3 4 5 6 |
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__().
1 2 3 4 5 6 7 8 9 10 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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
1 2 3 4 5 6 7 8 |
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.
1 2 3 4 5 6 7 8 9 |
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.
1 2 3 4 5 6 7 8 |
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.