41

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))
Georgy
  • 12,464
  • 7
  • 65
  • 73
yuenster
  • 413
  • 1
  • 4
  • 5
  • not familiar with the syntax you're using.. don't you mean ```def twoSum(nums, target):```? – ewokx Aug 18 '20 at 00:12
  • 1
    @ewong. It's type hints, and they're all the rage now – Mad Physicist Aug 18 '20 at 00:19
  • 6
    This syntax is supported from Python 3.9 onwards only – Jasmijn Aug 18 '20 at 01:35
  • Related: [Using List/Tuple/etc. from typing vs directly referring type as list/tuple/etc](https://stackoverflow.com/q/39458193/7851470). – Georgy Aug 18 '20 at 10:38
  • 2
    As other mentioned this will be supported in Python 3.9, but if you want to use this solution (like `list[int]`) earlier, you can do it by putting `from __future__ import annotations` as the first import of the module (available from Python 3.7+ because of [PEP 563](https://www.python.org/dev/peps/pep-0563/)). – Nerxis Apr 19 '21 at 20:44
  • See also: https://stackoverflow.com/questions/37087457 – Karl Knechtel Jul 06 '22 at 23:22

4 Answers4

56

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):
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • 4
    Typing hasn't used metaclasses since like 3.7 because typing code which used a different metaclass was impossible. `__class_getitem__` was added and is what is used to subscript types. Additionally your answer is completely wrong in Python 3.9+. – Peilonrayz Apr 04 '21 at 15:54
  • 1
    This just solved my problem. Ta a lot! – masher Dec 31 '21 at 13:34
  • @masher. Always happy to hear when things work out. Good luck! – Mad Physicist Dec 31 '21 at 18:09
  • If anyone is arriving at this solution using Pydantic and Python3.8, this is it; check for `list, dict` types and convert them to `List, Dict,` solved for me. – Kieleth Sep 17 '22 at 00:25
11

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.

dsz
  • 4,542
  • 39
  • 35
4

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.

Mark Volkmann
  • 909
  • 12
  • 15
2

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.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153