3

I would like to know if there is a way to get the code of the following lambda functions:

a = {"test": lambda x: x + 123, "test2": lambda x: x + 89}

Is there a way to like

print(getsource(a["test"])

That returns :

lambda x: x + 123

I'm already aware of inspect and dill getsource functions but the following code:

import inspect
import dill

if __name__ == "__main__":

    a = {"test": lambda x: x + 123, "test2": lambda x: x + 89}

    print(inspect.getsource(a["test"]))
    print(dill.source.getsource(a["test"]))

Returns:

a = {"test": lambda x: x + 123, "test2": lambda x: x + 89}

a = {"test": lambda x: x + 123, "test2": lambda x: x + 89}
mrnl
  • 51
  • 4
  • Doesn't `a["test"]` give you the code of the `lambda` function? – Julian Chan Dec 27 '19 at 09:50
  • Hi, thank you for you response, unfortunately no, I only get : at 0x000000000204C1E0> – mrnl Dec 27 '19 at 09:53
  • what exactly are you looking for? `lambda x: x +123` as a string? – Julian Chan Dec 27 '19 at 09:54
  • Yes, I would like to print the lambda function definition as a string. – mrnl Dec 27 '19 at 09:55
  • Does this solve your problem? https://stackoverflow.com/a/30984012/8268531 – Julian Chan Dec 27 '19 at 09:59
  • No because this answer manipulates the line returned by inspect.getsourcelined. For my problem, the line returned by this method is the same for both lambda functions. I could use this kind of trick to get the start of the lambda function but I think that it would be impossible to stop at the right place in the string to get the exact definition. – mrnl Dec 27 '19 at 10:08
  • Possible solution is to create one lambda function per line of code. Another option is to use `ast` module together with appropriate parser like `astunparse` project to analyze and modify source code. For example, see https://stackoverflow.com/questions/768634/parse-a-py-file-read-the-ast-modify-it-then-write-back-the-modified-source-c –  Dec 27 '19 at 13:20

2 Answers2

1

I ran into the same problem so I wrote a few code that I believe can at least partially address this.

def get_lambda_source(lambda_func, position):
    import inspect
    import ast
    import astunparse
    code_string = inspect.getsource(lambda_func).lstrip()
    class LambdaGetter(ast.NodeTransformer):
        def __init__(self):
            super().__init__()
            self.lambda_sources = []

        def visit_Lambda(self, node):
            self.lambda_sources.append(astunparse.unparse(node).strip()[1:-1])

        def get(self, code_string):
            tree = ast.parse(code_string)
            self.visit(tree)
            return self.lambda_sources
    return LambdaGetter().get(code_string)[position]

In your case,

print(get_lambda_source(a['test'], 0]))

returns

lambda x: x + 123

Note this doesn't work in the shell.

Yuze Lou
  • 23
  • 5
  • **Brilliant.** This is foolproof, which is nice. But this also requires the third-party `astunparse` package *and* is hideously slow, which is less than nice. [A comparable solution in the third-party `icontract` package behaves similarly but substitutes `astunparse` with `asttokens`](https://github.com/Parquery/icontract/blob/6fb85fe00e91a0b27369a543642d071feb7740d6/icontract/represent.py#L157). It's pick your poison either way, of course. `` – Cecil Curry Apr 17 '21 at 07:00
1

How about the following function mygetsource?

import inspect

def mygetsource(l, n):
    s = inspect.getsource(l[n])
    s = s[s.index('{')+1:-2]
    d = {x[1:x.index(':')-1]: x[x.index(':')+2:] for x in s.split(', ')}
    return d[n]

a = {"test": lambda x: x + 123, "test2": lambda x: x + 89}
print(mygetsource(a, "test"))
print(mygetsource(a, "test2"))
b = {'func1': lambda y: y * 10, 'func2': lambda z: z ** z}
print(mygetsource(b, "func1"))
print(mygetsource(b, 'func2'))

Below is the result:

lambda x: x + 123
lambda x: x + 89
lambda y: y * 10
lambda z: z ** z
evenodd
  • 317
  • 1
  • 8