I am using Python 3.5 together with Mypy to have some basic static checking for my script. Recently I refactored some methods to return OrderedDict, but ran into "'type' object is not subscriptable" error, when I tried to use return annotation with Key and Value types specified.
Reduced example:
#!/usr/bin/env python3.5
from collections import OrderedDict
# this works
def foo() -> OrderedDict:
result = OrderedDict() # type: OrderedDict[str, int]
result['foo'] = 123
return result
# this doesn't
def foo2() -> OrderedDict[str, int]:
result = OrderedDict() # type: OrderedDict[str, int]
result['foo'] = 123
return result
print(foo())
And this is python output when it is run:
Traceback (most recent call last):
File "./foo.py", line 12, in <module>
def foo2() -> OrderedDict[str, int]:
TypeError: 'type' object is not subscriptable
Mypy however has no problem with the type annotation in comment and will in fact warn if I try to do result[123] = 123
.
What is causing this?
There is no problem in mypy (at least, not in 0.501). But there is a problem with Python 3.6.0. Consider the following:
from collections import OrderedDict
from typing import Dict
def foo() -> Dict[str, int]:
result: OrderedDict[str, int] = OrderedDict()
result['two'] = 2
return result
This code will both satisfy mypy (0.501) and Python (3.6.0).
However, if you replace Dict
with OrderedDict
, then mypy will still be happy, but executing it will die with TypeError: 'type' object is not subscriptable
.
It is interesting that the Python interpreter dies on seeing a subscripted OrderedDict
in the function signature, but is happy to accept it in a variable type annotation.
At any rate, my workaround for this is to use Dict
instead of OrderedDict
in the function signature (and add a comment that this should be fixed if/when the Python interpreter will learn to accept the correct signature).
As a workaround, you can also put the return type into a string to satisfy both Mypy and Python 3.6:
from collections import OrderedDict
def foo() -> 'OrderedDict[str, int]':
result = OrderedDict()
result['foo'] = 123
return result
What you can also try is using MutableMapping
(like in this Answer: https://stackoverflow.com/a/44167921/1386610)
from collections import OrderedDict
from typing import Dict
def foo() -> MutableMapping[str, int]:
result = OrderedDict() # type: MutableMapping[str, int]
result['foo'] = 123
return result
I don't know which version allowed this, but a better solution as for March/24/2021, tested for Python 3.7.5:
from collections import OrderedDict
import typing
def foo() -> typing.OrderedDict[str, int]:
result: typing.OrderedDict[str, int] = OrderedDict()
result['two'] = 2
return result
Enjoy all worlds!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With