I've often wanted an anonymous function that would do more than return the result of an expression. So I developed one around the exec function that supports assignments and multiline lambdas but suspect a few things are missing. Suggestions would be appreciated, please.
I've tried to keep the syntax similar to a normal lambda and also easy to debug by copying the text into a standard function.
Tested with CPython 3.6.5 and Pypy 3.5.3. To give an idea of the current version, it is capable of evaluating these functions:
λ("""var: for i in range(var): print(i, end = ",") print(' ', end='') if i == var - 1: print(var) print(var) rtrn = [i for i in range(var, 0, -1)] """)(5) 0, 1, 2, 3, 4, 5 5 [5, 4, 3, 2, 1] λ("x: [x*i for i in range(x)]; print('Final:', rtrn[-1])")(3) Output: 6 [0, 3, 6] λ("x, y:: from math import cos, sin; rtrn = cos(x) + sin(y)")(3, 5) -1.9489167712635838
def lambda_(code): """ Anonymous function supporting multiple line and assignments. For one line the form is λ("parameters : code incl assignment")(*arguments) and the first exepression is assigned to rtrn which is returned For multiline, use triple quotes & the parameters must be on the first line, the : is followed directly by a line feed and then the code Input: code in the form "x, y,...: return_value_expression; other code" Output is assigned to variable rtrn """ def build_lambda(*args): """ All arguments are declared global as listcomps etc don't create closure when called using exec, so declare parameters & rtrn as globals Multiline will return None unless you assign rtrn a value. """ val_idx, val_name = 0,  i, parameters = -1,  if ":" in code: for i, c in enumerate(code): # loop until the : that ends parameters if c in ",:": if val_name: parameters.append(''.join(val_name)) val_name =  val_idx += 1 if c == ":": break elif c != " ": val_name.append(c) # exec_code sets rtrn = None for multiline or sets rtrn = first expression for # single line unless :: (used if first expression can't be evaluated) if code[i+1] != "\n": # single line, if code[i+1] != ":": exec_code = ''.join(("rtrn = ", code[i+1:])) else: exec_code = ''.join(("rtrn = None; ", code[i+2:])) else: # multiline # wont run if excess leading spaces so remove them lead = 0 code_ = code[i+1:] while code_[lead+1] == " ": # how many on 1st line? lead += 1 for i in range(1, len(code_)): # remove that on all lines if code_[i-1: i+1] == "\n ": code_ = code_[: i] + code_[i+lead:] exec_code = "rtrn = None" + "\n" + code_ # executable code define_globals = ', '.join(["global rtrn"] + parameters) assign = [' = '.join((p, str(args[i]))) for i, p in enumerate(parameters)] assign = '; '.join(assign) cmd = '; '.join((define_globals, assign if assign else "pass", exec_code)) if args and args[-1] == "print": print(cmd, "\n") exec(cmd) return rtrn return build_lambda λ = lambda_ # rebind to linux ctrl+shift+u 03BB
With the added complexity it seems more reasonable to create a class splitting code generation, execution and printing. The code is posted in this question.