-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Loop Variable over Literal List Not Recognised as Having Literal Type #18826
Comments
use a tuple instead of a list |
I agree the first should work but IMO the second is bad -- remember that |
As a general rule, I try to maintain a semantic distinction between tuples and lists: tuples are used to collect unlike elements of related data together so they can be manipulated as a single object, whereas lists are used to collect a sequence of common items for iteration. I'll use the 'wrong' type if I have to, e.g. converting a list to a tuple if I need to use it as a dictionary key, or using a list to assemble the pieces of related data one-by-one before I then convert them to a tuple once complete. While, in this case, a tuple and a one-off list literal are functional identical, a list is clearly semantically more appropriate, so I'd prefer to use one.
In the general case, yes. I would absolutely not expect this to pass muster: ls = ["foo", "bar"]
d: MyLiteral
for d in ls:
func(d) But in the specific case where a list-literal is being used as the iterable of a for-loop, it makes more sense to infer the type as specifically as possible. It doesn't matter that There's already precedent for making exactly this kind of distinction: def func3(l1: list[MyLiteral]):
...
func3(["foo", "bar"])
fs1: frozenset[MyLiteral] = frozenset(["foo", "bar"])
l = ["foo", "bar"]
func3(l)
fs2: frozenset[MyLiteral] = frozenset(l) The first call to Hell, if we just assumed that the implicit type of |
Now, I can see one potential issue with my proposal: for phonetic_letter in [
"Alpha",
"Bravo",
"Charlie",
"Delta",
"Echo",
"Foxtrot",
"Golf",
"Hotel",
"India",
"Juliet",
"Kilo",
"Lima",
"Mike",
"November",
"Oscar",
"Papa",
"Quebec",
"Romeo",
"Sierra",
"Tango",
"Uniform",
"Victor",
"Whiskey",
"X-ray",
"Yankee",
"Zulu",
]:
print(f"The NATO phonetic name for {phonetic_letter[1]} is {phonetic_letter!r}")
_tp.reveal_type(phonetic_letter) What should
I can see 3 general solutions:
(Side note: Anybody else wish MyPy was better about using concise forms for type names? Because that entire 482-char |
I think you're misunderstanding that issue. It's about iterating over specifically tuples for literal keys. |
Okay, fair enough, I missed that in that case it is looping over a tuple rather than over a list. Option 3 on what to do about However, I feel my original point stands: the implicit type of a loop variable when iterating over a list-literal should use as narrow a type as possible. |
Bug Report
When a for-loop is used to iterate over a list-literal (or other collection-literal) which contains only scalar literals, then MyPy should be smart enough to recognize that the implicit type of the loop variable is not merely the type of the values in the list but the specific values in that list.
To Reproduce
Expected Behavior
b
are compatible with its explicit type ofMyLiteral
, the same way it identifies that the values being assigned toa
on lines 10 & 12 are legal.c
asLiteral["foo", "bar"]
, which is compatible with the first argument offunc()
Actual Behavior
Your Environment
mypy 1.5.1 (compiled: yes)
mypy.ini
(and other config files): NonePython 3.11.2
Related Issues
TypedDict
. A fix was applied which solved the problem, but only for the special-case of accessing members ofTypedDict
, not for other, similar cases such as using the loop variable as a function argument as in the above exampleThe text was updated successfully, but these errors were encountered: