The fact that it works with literals as parameters seems surprising, since List[1,2,3] gives a TypeError. I wonder if that’s intentional. The PEP doesn’t mention this behavior.
No they are not strings, calling repr gives you a string, and you would get a string for any object.
And this was not a SyntaxError in the past but a TypeError.
Is this a problem because you thought you created a list but actually ended up creating a GenericAlias? Then you would have realized your mistake pretty soon, as soon as you try to use the value anywhere later in your code, so it is not a very big deal. There are lots of other cases where you cannot rely on the interpreter to catch your mistake at the point where it was made and you have to find out later, for example the trailing comma making a tuple.
On the other hand, you get benefits of static type checking which does help you find the errors early without even running your code. If you had used a static type checker it would have caught this mistake for you.
You are right that I didn’t check what type of error would an older Python give me and you are right that my inspection of the resulting type was wrong.
Nevertheless the discussed issue may be a big deal in a larger codebase and the error may appear quite far from the wrong line of code. Static checker may sometimes help in such case, you are right again.
But It took me quite long to discover, because list[] and list() are visually similar, and the error was an if condition with comparison that never evaluated True. In my case static checker would not help at all.
IMHO it should not be considered an issue because it is a valid way how to specify a type variable. Example of how it could be used at run time:
>>> from typeguard import check_type
>>> x = list[int]
>>> check_type('test_list', [1, 2, 3], x)
>>> check_type('test_list', ['a', 'b'], x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/vbrozik/tmp/python/typeguard/.venv/lib/python3.10/site-packages/typeguard/__init__.py", line 757, in check_type
checker_func(argname, value, expected_type, memo)
File "/home/vbrozik/tmp/python/typeguard/.venv/lib/python3.10/site-packages/typeguard/__init__.py", line 458, in check_list
check_type('{}[{}]'.format(argname, i), v, value_type, memo)
File "/home/vbrozik/tmp/python/typeguard/.venv/lib/python3.10/site-packages/typeguard/__init__.py", line 785, in check_type
raise TypeError(
TypeError: type of test_list[0] must be int; got str instead
typeguard.check_type() raises TypeError when the type does not match.
Note: list[1, 2, 3] is not a valid type specification.
But it is valid syntax. Perhaps the question should be, in what circumstance (if any) is list[1,2,3] useful? If the answer is “never”, shouldn’t the interpreter complain about it?
That said, if too many people are tripped by this behavior it may make sense to add a runtime check for this. But I feel this causes issues rarely and it is easy to catch later in your code because GenericAlias will behave very differently from the object you expected to create, and once you learn about this behavior you won’t repeat the mistake.
Ah, yes, you are right. That’s not generalizable though, since for example dict takes two arguments. I imagine checking all such possibilities at runtime would be expensive.