"TypeError: 'type' object is not subscriptable" in a function signature

Question:

Why am I receiving this error when I run this code?

Traceback (most recent call last):                                                                                                                                                  
  File "main.py", line 13, in <module>                                                                                                                                              
    def twoSum(self, nums: list[int], target: int) -> list[int]:                                                                                                                    
TypeError: 'type' object is not subscriptable
nums = [4,5,6,7,8,9]
target = 13

def twoSum(self, nums: list[int], target: int) -> list[int]:
        dictionary = {}
        answer = []
 
        for i in range(len(nums)):
            secondNumber = target-nums[i]
            if(secondNumber in dictionary.keys()):
                secondIndex = nums.index(secondNumber)
                if(i != secondIndex):
                    return sorted([i, secondIndex])
                
            dictionary.update({nums[i]: i})

print(twoSum(nums, target))
Asked By: yuenster

||

Answers:

The following answer only applies to Python < 3.9

The expression list[int] is attempting to subscript the object list, which is a class. Class objects are of the type of their metaclass, which is type in this case. Since type does not define a __getitem__ method, you can’t do list[...].

To do this correctly, you need to import typing.List and use that instead of the built-in list in your type hints:

from typing import List

...


def twoSum(self, nums: List[int], target: int) -> List[int]:

If you want to avoid the extra import, you can simplify the type hints to exclude generics:

def twoSum(self, nums: list, target: int) -> list:

Alternatively, you can get rid of type hinting completely:

def twoSum(self, nums, target):
Answered By: Mad Physicist

The answer given above by "Mad Physicist" works, but this page on new features in 3.9 suggests that "list[int]" should also work.

https://docs.python.org/3/whatsnew/3.9.html

But it doesn’t work for me. Maybe mypy doesn’t yet support this feature of 3.9.

Answered By: Mark Volkmann

Lifting the comment from @Nerxis into an answer.

For Python 3.7 and 3.8, add:

from __future__ import annotations

as your first import into your module.

While the accepted answer of using List instead of list is fine, it won’t help you when you need to do pd.Series[np.int64]. Use the above instead.

Answered By: dsz

Summary

The part of the code that says -> list[int] is a type annotation for the return type of the function. It is a special notation that can be used by third-party tools to do some basic static type-checking on the code. The only effect it has on the code, as far as Python itself is concerned, is to add some metadata to the function:

>>> def example() -> list[int]:
...     pass
... 
>>> 'return' in example.__annotations__
True

Python itself will not do any type checking.

Similarly, the : list[int] part is a type annotation for the nums parameter for twoSum.

Depending on the Python version, this specific annotation may not be accepted.

Python 3.9 and above

The error is not reproducible. -> list[int] declares that the function is intended to return a list that contains all integer values, and : list[int] declares that another such list should be passed in for nums. These hints allow third-party tools like MyPy to look for problems before the code is compiled or run.

Python 3.7 or 3.8

This annotation is not accepted as-is. There are two workarounds:

  1. Use a __future__ import, to access the "postponed evaluation of annotations" behaviour described in PEP 563:
# At the top of the code, along with the other `import`s
from __future__ import annotations
  1. Use the corresponding class defined in the standard library typing module:
# At the top of the code
from typing import List

# when annotating the function
def twoSum(self, nums: List[int], target: int) -> List[int]:

Note the capital L in List.

Python 3.5 and 3.6

The __future__ annotation is not supported. Use the typing module.

Python 3.4 and below

Type annotations are not supported at all. Simply remove them:

def twoSum(self, nums, target):

Again, remember that Python itself does not do anything meaningful with the annotations. They will not cause the code to raise exceptions for invalid parameters, convert them to the correct type, or anything else like that. They are only for third-party tools, and completely optional unless some other third-party tool is forcing their use.

Answered By: Karl Knechtel