The syntax might be made more readable by requiring some (soft) keywords, e.g., do
and passing
(or any other pair of keywords; the point is that the first would be the callback placeholder and the other would be a well visible indicator of the entire construct, preceding the callback’s parameters, if any):
foo(do, x=1) passing a, b, c:
print(a, b, c)
retry(do, n=3) passing:
do_something()
my_list.sort(key=do) passing item:
return x**3 - 2x + 1
last_first_name = re.sub(r'(\w+) (\w+)', do, first_last_name) passing match:
first_name, last_name = match.groups()
return f'{last_name}, {first_name}'.upper()
parsed = map(do, unparsed) passing raw_item:
head, sep, tail = raw_item.partition('-')
if sep:
return [head, tail]
return [head]
x = 13 if some_test() else fn(1, 2, do) passing a, b:
return a + b
x = (fn(1, 2, do) if some_test() else 13) passing a, b:
return a + b
When it comes to non-operator syntax elements, Python seems to like keywords more than punctuation…
But, regardless of the syntax details, the main problem I see with this whole approach is that when we need to make our callback return some values (as in the most of the above examples), the return
statement may look as it was returning from the enclosing scope, i.e., it is not clear enough (visually) that return
belongs to the inner definition of the callback. Consider this:
def adjust_names(text):
output = re.sub(r'(\w+)\s+(\w+)', do, text) passing match:
first_name, last_name = match.groups()
if first_name.lower() == 'johnny':
return f'{last_name}, John Jr.'.upper()
return f'{last_name}, {first_name}'.upper()
if output == text:
return 'Nothing interesting...'
return output
It is not obvious at the first sight which return
returns from the callback and which from the enclosing function.
However, have you read PEP 3150 and PEP 403 by Alyssa Coghlan? Each of those documents answers in its own way to that problem, and I found both of them very interesting. Even if they are not exactly the solution you seek for, maybe you can take some inspiration from them?