A less limited Python Lambda 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 &amp; 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 &amp; 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.
Naming:


λ is not a standard Python function name ([a-z] followed by [a-z0-9_]+) and will require figuring out some magic sequence in non-Greek keyboard layouts.
s0, s1, s2, lead and cd should be renamed to be more intuitive. For example, based on your documentation s1 could be named something like assignments.


General:


Rather than adding strings and newlines together I'd use format() and join(). It's easier to follow the construction of the string that way.
I would not recommend using this in production code. Treating strings as code is going to result in many more runtime errors which will be harder to debug than the corresponding named function.
λ does not accept functions without parameters - λ('print("value")')() for example results in IndexError.
Code construction and execution should be split up for easier debugging. I should be able to run construct_code(my_code_string) and see what would be executed for debugging.
I don't have the time to test this myself, but you should be able to get rid of the global rtrn by constructing an actual function and running that instead of creating global code.