3
\$\begingroup\$
def parse_names(tex_names: list[str]) -> set[str]:
 # the list comprehension in question
 return set(parsed_name for parsed_name in [_parse_name(tex_name) for tex_name in tex_names] if parsed_name)
def _parse_name(tex_name: str) -> Optional[str]:
 tex_regex = re.compile(r"^%? ?([\w() äöüÄÖÜß]+)( \((ab|bis) \d{2}:\d{2} Uhr\))?,")
 match = tex_regex.match(tex_name)
 if match:
 return match.groups()[0]
 return None

with test

def test_parse_names():
 raw_names = [
 "% Valid Name,",
 " Without percent,",
 "Without space,",
 "% Another (valid) name,",
 "% Max Mustermann (ab 13:00 Uhr),",
 "% Maxi Mustermann (bis 14:00 Uhr),",
 "% Mara Musterfrau (von 13:00 Uhr),", # invalid
 "% Lara Musterfrau von 13:00 Uhr,", # invalid
 "12345", # invalid
 "%% some message", # invalid
 "Missing comma", # invalid
 ]
 expected = {
 "Valid Name",
 "Without percent",
 "Without space",
 "Another (valid) name",
 "Max Mustermann",
 "Maxi Mustermann"
 }
 actual = parse_names(raw_names)
 assert actual == expected

Is it possible to simplify the list comprehension while maintaining correct typing? E.g.

def parse_names(tex_names: list[str]) -> set[str]:
 return set(_parse_name(tex_name) for tex_name in tex_names if _parse_name(tex_name))

works just fine, but triggers the mypy error

error: List comprehension has incompatible type List[Optional[str]]; expected List[str]
mdfst13
22.4k6 gold badges34 silver badges70 bronze badges
asked Sep 24, 2022 at 16:37
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

Mypy doesn't know that calling _parse_name multiple times will always return the same value if the same value is passed to it. You could try using walrus operator so it uses the value returned specifically for the truthiness check:

return set(value for tex_name in tex_names if (value := _parse_name(tex_name)))

This is also better because it avoids needing to call the function twice.

However, since all you're doing is passing each value to a function and checking the returned value's truthiness, you could use map and filter instead:

return set(filter(None, map(_parse_name, tex_names)))
answered Sep 24, 2022 at 17:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.