70

I'd like to be able to print the definition code of a lambda function.

Example if I define this function through the lambda syntax:

>>>myfunction = lambda x: x==2
>>>print_code(myfunction)

I'd like to get this output:

x==2
Mapad
  • 8,407
  • 5
  • 41
  • 40
  • 2
    Please use `def x( args )` instead of `x= lambda( args )`. This doesn't answer your question, but please use def's for this. – S.Lott Dec 02 '08 at 18:00
  • 2
    Since this post is marked as duplicate it is not possible to post answers anymore. However the duplicate post concerns plain functions, not lambdas. I posted an answer specific to lambdas here: https://stackoverflow.com/a/55760092/7262247 – smarie Apr 19 '19 at 10:05
  • I found it easier to capture the desired function as a string, then evaluate it in my lambda function e.g.where f is a string defining the function: map(lambda x: eval(f), x). In this way the function is defined once but still available as text. – James Nov 02 '19 at 22:32

6 Answers6

91

As long as you save your code to a source file you can retrieve the source code of an object using the inspect module.

example: open editor type:

myfunction = lambda x: x==2

save as lamtest.py

open shell type python to get to interactive python type the following:

>>>from lamtest import myfunc
>>>import inspect
>>>inspect.getsource(myfunc)

the result:

'myfunc = lambda x: x==2\n'
pcn
  • 1,007
  • 7
  • 2
  • 5
    Any idea on why it cannot work in the python shell? – noamtm Dec 03 '08 at 13:03
  • 8
    it doesn't work in the shell because the code is not defined in a file, inspect looks at the __file__ attribute and opens that file and reads it. – Moe Dec 03 '08 at 15:53
  • works in IPython, nice – Roman Plášil Dec 11 '13 at 03:03
  • 2
    @MartinVilcans Yeah! You can even fly: terminal --> python [enter] import antigravity :) Seriously – dylnmc Oct 25 '14 at 02:56
  • 1
    It is cool, unfortunately it does not work if the lambda was not generated from a real file. For e.g. it raises an "IOError: could not get source code" if you use it from strings or the console. – Sven Aug 04 '16 at 10:14
  • 2
    This doesn't exactly answer the question. Is there a way to get just ``x==2`` instead of the full source code surrounding the declaration? – dom96 Sep 07 '16 at 12:05
27

It will only work for mathematical based operations, but you might look at SymPy's Lambda() object. It was designed exactly for this purpose:

>>> from sympy import *
>>> x = Symbol('x')
>>> l = Lambda(x, x**2)
>>> l
Lambda(_x, _x**2)
>>> l(3)
9

It even supports pretty printing:

>>> pprint(l)
 ⎛    2⎞
Λ⎝x, x ⎠

To do your equals example, us the SymPy Eq() object:

>>> l1 = Lambda(x, Eq(x, 2))
>>> l1
Lambda(_x, _x == 2)
>>> l1(2)
True

It supports partial argument expansion:

>>> y = Symbol('y')
>>> l2 = Lambda((x, y), x*y + x)
>>> l2(1)
Lambda(_y, 1 + _y)
>>> l2(1, 2)
3

And of course, you get the advantage of getting all of SymPy's computer algebra:

>>> l3 = Lambda(x, sin(x*pi/3))
>>> pprint(l3(1))
  ⎽⎽⎽
╲╱ 3 
─────
  2  

By the way, if this sounds like a shameless plug, it's because it is. I am one of the developers of SymPy.

asmeurer
  • 86,894
  • 26
  • 169
  • 240
  • sympy is an amazing piece of sofware, shameless not to use it! thank you very much :) – fr_andres Sep 02 '17 at 01:53
  • Note that if the function is not necessarily mathematics-oriented or is simple, `mini_lambda` offers a light mono-variable alternative to SymPy: https://stackoverflow.com/a/55760092/7262247 – smarie Apr 19 '19 at 10:07
22

While I'd generally agree that inspect is a good answer, I'd disagree that you can't get the source code of objects defined in the interpreter. If you use dill.source.getsource from dill, you can get the source of functions and lambdas, even if they are defined interactively. It also can get the code for from bound or unbound class methods and functions defined in curries... however, you might not be able to compile that code without the enclosing object's code.

>>> from dill.source import getsource
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getsource(add)
def add(x,y):
  return x+y

>>> print getsource(squared)
squared = lambda x:x**2

>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getsource(f.bar)
def bar(self, x):
    return x*x+x

>>> 
Mike McKerns
  • 33,715
  • 8
  • 119
  • 139
  • This module doesn't seem to work with Jupyter notebooks, FYI - see [here](https://github.com/uqfoundation/dill/issues/54). – abe Apr 10 '20 at 13:20
9

That will be very difficult, because your lambda function will be compiled to bytecode, and your myfunction object will only be pointing to the bytecode and not the human-readable code that you wrote.

For example, if you define 2 functions, one using lambda syntax and one using a def statement, as follows:

>>> lambda_func = lambda x: x==2
>>> def def_func(x): return x == 2
...

These 2 objects (lambda_func and def_func) will be equivalent as far as python is concerned. In fact, if you go ahead and disassemble them using the dis module (as rebra suggested), you will get identical results:

>>> import dis
>>> dis.dis(lambda_func)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (2)
              6 COMPARE_OP               2 (==)
              9 RETURN_VALUE
>>> dis.dis(def_func)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (2)
              6 COMPARE_OP               2 (==)
              9 RETURN_VALUE

That being the case, you can see how it would be difficult to obtain the original code when it's a many to one relationship

twasbrillig
  • 17,084
  • 9
  • 43
  • 67
Moe
  • 28,607
  • 10
  • 51
  • 67
2

How's this?

class MyLambda( object ):
    def __init__( self, body ):
        self.body= body
    def __call__( self, arg ):
        x = arg
        return eval( self.body )
    def __str__( self ):
        return self.body

f= MyLambda( "x == 2" )
print f(1)
print f(2)
print f
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • Compared to the solution from pcn, this works in the console, even if you've deleted the source code. The only downside of this is that you need to put the code in a string... – Mapad Dec 03 '08 at 08:45
  • @Mapad: Not a downside. The only way to satisfy your requirement without modding the Python compiler to save source in a docstring. – S.Lott Dec 03 '08 at 10:37
-7

Why do you want to do this?

I guess you could use the "dis" module to disassemble your code to python bytecode, but it's probably not what you want.

http://www.python.org/doc/2.5.2/lib/module-dis.html

Again, I can't see the use case for this. Perhaps eval() is more suited for your problem. It is built in, and then you can use strings to pass code around in your code.

rebra
  • 1,082
  • 2
  • 7
  • 16
  • 1
    I've built a state machine. The conditions to go from one state to another are defined by lambda functions. I wanted to plot a graph of this state machine, with the lambda functions on top of each arc. – Mapad Dec 03 '08 at 08:33
  • Sadly python decompilers are in rather poor state, there's one for <=2.5 out there. – Dima Tisnek Jul 13 '12 at 11:14
  • Another use case would be a form of enhanced automatic documentation - Lambda's are sometimes used as default values in functions/methods (for instance sorts etc). It would be useful for an automated documentor to be able to list the lamda source code when documenting the function/method signature. – Tony Suffolk 66 Dec 04 '15 at 04:13
  • 8
    Down voted this answer because, I personally feel an answer should not start with "Why do you want to do this?". – Codious-JR Mar 12 '19 at 15:43