There are many ugly recipes about to handle the common use case that could be handled by:

def findfirst(regex, text, default=None, flags=0):
     return next(finditer(regex, text, flags=flags), default=default)

The matching and return value semantics would be the same as those of re.findall(), but the search would stop on the first match, or return "default" if there wasn't a match (findfirst() will return a tuple when more than one group is matched).

Typically programmers will use:

matched = re.findall(regex, text)[0]

which is inefficient, and incorrect when there is no match.

Typically, the pattern for the use case will be:

m = re.search(regex, text)
if m:
     matched = m.groups()
else:
     matched = default
nowadays:

matched = m.groups() if (m := re.search(regex, text)) else default

The semantics of findall() are nicer, and so would be those of findfirst().

--
Juancarlo Añez