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

5

55

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))
Diocese answered 18/8, 2020 at 0:7 Comment(6)
not familiar with the syntax you're using.. don't you mean def twoSum(nums, target):?Slide
@ewong. It's type hints, and they're all the rage nowAdjudge
This syntax is supported from Python 3.9 onwards onlyEstrada
Related: Using List/Tuple/etc. from typing vs directly referring type as list/tuple/etc.Owing
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).Perineum
See also: stackoverflow.com/questions/37087457Algar
A
65

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):
Adjudge answered 18/8, 2020 at 0:13 Comment(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+.Lazaro
This just solved my problem. Ta a lot!Salomon
@masher. Always happy to hear when things work out. Good luck!Adjudge
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.Twofold
P
21

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.

Pattison answered 1/2, 2023 at 23:38 Comment(1)
The error at import time about pd.Series[type] or NDArray[type] for example, is still present in python 3.10 for me and this fixed it .Pseudocarp
A
8

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:

>>> type(example()) # definitely did not give a list of integers!
<class 'NoneType'>

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.

Algar answered 21/3, 2023 at 12:21 Comment(0)
A
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.

Achromaticity answered 23/10, 2020 at 11:30 Comment(3)
My code runs fine with list[int] in 3.9 (no runtime error), but still doesn't type check correctly with mypy.Blaspheme
Same here, list[int] works fine in 3.9, but raises the OP's error under Python3.8 (specifically the AWS Lambda Python3.8 runtime).Disabuse
In a venv \w python3 version 3.9.2, I still get the errorVallery
S
0

I've run into a similar problem while executing a Python script via python -m <package>.<module>. I was able to avoid it by switching from PowerShell to cmd. Maybe this happened because PowerShell used a different Python-Version than my cmd, which I was unable to check. (Windows 10 + Python 3.10)

Sowers answered 24/5 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.