613

Suppose I have a Python function as defined below:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

I can get the name of the function using foo.func_name. How can I programmatically get its source code, as I typed above?

Vertexwahn
  • 7,709
  • 6
  • 64
  • 90
  • 3
    Note, in Python 3 you can get the function name using `foo.__name__` – MikeyE Apr 29 '18 at 07:35
  • You can get a [lot of other things](https://docs.python.org/2/library/inspect.html) as well. – not2qubit Oct 21 '18 at 15:55
  • 3
    Possible duplicate of [How do you get Python to write down the code of a function it has in memory?](https://stackoverflow.com/questions/399991/how-do-you-get-python-to-write-down-the-code-of-a-function-it-has-in-memory) – recnac Apr 28 '19 at 01:40

15 Answers15

767

If the function is from a source file available on the filesystem, then inspect.getsource(foo) might be of help:

If foo is defined as:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a  

Then:

import inspect
lines = inspect.getsource(foo)
print(lines)

Returns:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a                

But I believe that if the function is compiled from a string, stream or imported from a compiled file, then you cannot retrieve its source code.

Smart Manoj
  • 5,230
  • 4
  • 34
  • 59
Rafał Dowgird
  • 43,216
  • 11
  • 77
  • 90
  • 4
    [Returns](https://docs.python.org/2/library/inspect.html#inspect.getsourcelines) a tuple; tuple[0] is list of strings representing the lines of source code, and tuple[1] is the line number in the context of execution where it was run. In IPython; this is the line number within the *cell* not the overall *notebook* – Nate Anderson Sep 23 '14 at 05:32
  • 19
    This answer doesn't explicitly mention it, but inspect.getsource(foo) returns the source in a single string instead of a tuple where tuple[0] is a list of the lines. getsource will be more useful if you need to peek in the repl – whaley Aug 23 '15 at 13:49
  • it doesn't work with e.g. the function `len`. Where can I find the source code for the `len` function? – oaklander114 Sep 15 '16 at 06:06
  • 6
    or `inspect.getsourcelines(foo)` – Sławomir Lenart Oct 17 '18 at 10:59
  • 4
    @oaklander113 inspect.getsource doesn't work with built-ins like most of the functions from the standard library. You can check the source code for cpython at [their website](https://www.python.org/downloads/source/) or [their Github](https://github.com/python/cpython) – Nicolas Abril Sep 23 '19 at 18:32
  • You could also `.split('\n')`, as I show here: https://github.com/cgi1/Cheats/blob/master/inspect_another_python_function.py – gies0r Jul 27 '20 at 21:49
  • It is in fact possible to retrieve source code for a function dynamically compiled from a string. See [my answer](https://stackoverflow.com/a/69005706/3047698). – mtoor Aug 31 '21 at 21:58
  • Not only will this not retrieve source for all situations, (eg functions that are not defined in a source file whether builtin, exec, or something else), but whether what it *does* retrieve is correct depends on your definition of "source". For example this won't show you the transformed result of a function after passing through a decorator. – George Mauer Sep 03 '21 at 03:42
  • What if it is a class and you want to print a specific method associated with it? – Shmack Sep 24 '21 at 05:35
236

The inspect module has methods for retrieving source code from python objects. Seemingly it only works if the source is located in a file though. If you had that I guess you wouldn't need to get the source from the object.


The following tests inspect.getsource(foo) using Python 3.6:

import inspect

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

source_foo = inspect.getsource(foo)  # foo is normal function
print(source_foo)

source_max = inspect.getsource(max)  # max is a built-in function
print(source_max)

This first prints:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

Then fails on inspect.getsource(max) with the following error:

TypeError: <built-in function max> is not a module, class, method, function, traceback, frame, or code object
André C. Andersen
  • 8,955
  • 3
  • 53
  • 79
runeh
  • 3,771
  • 1
  • 21
  • 16
148

Just use foo?? or ??foo.

If you are using IPython, then you need to type foo?? or ??foo to see the complete source code. To see only the docstring in the function, use foo? or ?foo. This works in Jupyter notebook as well.

In [19]: foo??
Signature: foo(arg1, arg2)
Source:
def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

File:      ~/Desktop/<ipython-input-18-3174e3126506>
Type:      function
prashanth
  • 4,197
  • 4
  • 25
  • 42
  • 26
    Very helpful in IPython and Jupyter notebook if/when you accidentally delete more than one cell that contains functions you've just spent the day creating and testing.... – AGS Jun 28 '16 at 13:22
  • 6
    To whom, who lost the whole class: you can restore it method by method: `dir(MyClass)`, then `MyClass.__init__??` and so on. – Valerij May 08 '19 at 12:32
  • @Valerij could youplease elaborate more? – Max Nov 14 '21 at 03:25
92

dis is your friend if the source code is not available:

>>> import dis
>>> def foo(arg1,arg2):
...     #do something with args
...     a = arg1 + arg2
...     return a
...
>>> dis.dis(foo)
  3           0 LOAD_FAST                0 (arg1)
              3 LOAD_FAST                1 (arg2)
              6 BINARY_ADD
              7 STORE_FAST               2 (a)

  4          10 LOAD_FAST                2 (a)
             13 RETURN_VALUE
schlamar
  • 9,238
  • 3
  • 38
  • 76
76

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
  • 7
    @Ant6n: well, that's just being sneaky. `dill.source.getsource` inspects the interpreter's history for functions, classes, lambdas, etc -- it doesn't inspect the content of strings passed to exec. – Mike McKerns Mar 04 '14 at 03:04
  • This seems very interesting. Is it possible to use `dill` to answer this question: http://stackoverflow.com/questions/13827543/is-there-anyway-to-get-the-names-of-passed-arguments-to-a-function-in-python – ArtOfWarfare Feb 20 '15 at 16:34
  • 1
    @ArtOfWarfare: partially, yes. `dill.source` has functions like `getname` and `importable` and `getsource` that focus on getting the source code (or an importable that yields the object) for any given object. For simple things like an `int` there is *no* source, so it doesn't work as expected (i.e. for 'a = 10' it returns '10'). – Mike McKerns Feb 20 '15 at 18:08
  • 1
    This does work for globals however: ```>>> a = 10; print( [key for key, val in globals().items() if val is a][0] ) ``` – Mike McKerns Feb 20 '15 at 18:08
  • @MikeMcKerns: I've done my best to answer that question without using `dill`, but my answer leaves a bit to be desired (IE, if you have multiple names for the same value, it can't figure out which was used. If you pass in an expression, it can't say what that expression was. Heck, if you pass in an expression that evaluates to the same as a name, it'll give that name instead.) Can `dill` solve any of those shortcomings of my answer here: http://stackoverflow.com/a/28634996/901641 – ArtOfWarfare Feb 20 '15 at 18:24
  • @ArtOfWarfare: `dill.source` leverages `inspect` for code defined in a file.. and parses the interpreter's memory buffer for code defined in the interpreter. That could probably help you pick up the right name for several objects (see the above answer for an example with `lambda`). No idea how to do this for `a = 1` at this point, however. I do like your answer to the question you've linked above. – Mike McKerns Feb 20 '15 at 19:36
  • @MikeMcKerns: Thanks for mentioning that it uses the interpreter's memory buffer. I checked the source code and realized it's just using `readline`. I played with it on OS X and it works brilliantly. Unfortunately, I get an ImportError on Windows... have to find out if an equivalent module is available for Windows. I'll probably update the answer I already linked to with some code utilizing `readline` later. Edit: Oh, just found `pyreadline` for Windows. Haven't played with that yet. – ArtOfWarfare Feb 20 '15 at 22:14
  • @ArtOfWarfare Yes, `pyreadline` works on Windows just like readline on linux (at least, for the basic stuff). You even import it as `import readline`, although you install it as `pip install pyreadline`. – Josiah Yoder Jul 28 '20 at 14:13
  • @ArtOfWarfare Sadly, dill does not, as of 0.3.2, use pyreadline, and thus fails on methods defined at the Python prompt on Windows. – Josiah Yoder Jul 28 '20 at 14:17
  • @ArtOfWarfare: No, `dill` uses `pyreadline`. It's even available as an optional pip install. – Mike McKerns Jul 29 '20 at 11:08
22

To expand on runeh's answer:

>>> def foo(a):
...    x = 2
...    return x + a

>>> import inspect

>>> inspect.getsource(foo)
u'def foo(a):\n    x = 2\n    return x + a\n'

print inspect.getsource(foo)
def foo(a):
   x = 2
   return x + a

EDIT: As pointed out by @0sh this example works using ipython but not plain python. It should be fine in both, however, when importing code from source files.

TomDotTom
  • 6,238
  • 3
  • 41
  • 39
  • 4
    This won't work, since the interpreter would compile foo to bytecode and throw away the source code, raising an OSError if you try running `getsource(foo)`. – Milo Wielondek Feb 07 '15 at 18:14
  • @0sh good point as far as the vanilla python interpreter is concerned. However the above code example works when using IPython. – TomDotTom Jun 26 '15 at 09:04
16

Since this post is marked as the duplicate of this other post, I answer here for the "lambda" case, although the OP is not about lambdas.

So, for lambda functions that are not defined in their own lines: in addition to marko.ristin's answer, you may wish to use mini-lambda or use SymPy as suggested in this answer.

  • mini-lambda is lighter and supports any kind of operation, but works only for a single variable
  • SymPy is heavier but much more equipped with mathematical/calculus operations. In particular it can simplify your expressions. It also supports several variables in the same expression.

Here is how you can do it using mini-lambda:

from mini_lambda import x, is_mini_lambda_expr
import inspect

def get_source_code_str(f):
    if is_mini_lambda_expr(f):
        return f.to_string()
    else:
        return inspect.getsource(f)

# test it

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

print(get_source_code_str(foo))
print(get_source_code_str(x ** 2))

It correctly yields

def foo(arg1, arg2):
    # do something with args
    a = arg1 + arg2
    return a

x ** 2

See mini-lambda documentation for details. I'm the author by the way ;)

smarie
  • 4,568
  • 24
  • 39
  • See also https://stackoverflow.com/questions/334851/print-the-code-which-defined-a-lambda-function?noredirect=1#comment124424657_334851 – user202729 Dec 17 '21 at 03:39
12

You can use inspect module to get full source code for that. You have to use getsource() method for that from the inspect module. For example:

import inspect

def get_my_code():
    x = "abcd"
    return x

print(inspect.getsource(get_my_code))

You can check it out more options on the below link. retrieve your python code

Szabolcs
  • 3,990
  • 18
  • 38
Krutarth Gor
  • 157
  • 1
  • 3
8

Please mind that the accepted answers work only if the lambda is given on a separate line. If you pass it in as an argument to a function and would like to retrieve the code of the lambda as object, the problem gets a bit tricky since inspect will give you the whole line.

For example, consider a file test.py:

import inspect

def main():
    x, f = 3, lambda a: a + 1
    print(inspect.getsource(f))

if __name__ == "__main__":
    main()

Executing it gives you (mind the indention!):

    x, f = 3, lambda a: a + 1

To retrieve the source code of the lambda, your best bet, in my opinion, is to re-parse the whole source file (by using f.__code__.co_filename) and match the lambda AST node by the line number and its context.

We had to do precisely that in our design-by-contract library icontract since we had to parse the lambda functions we pass in as arguments to decorators. It is too much code to paste here, so have a look at the implementation of this function.

marko.ristin
  • 643
  • 8
  • 6
7

to summarize :

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
douardo
  • 697
  • 6
  • 6
5

If you're strictly defining the function yourself and it's a relatively short definition, a solution without dependencies would be to define the function in a string and assign the eval() of the expression to your function.

E.g.

funcstring = 'lambda x: x> 5'
func = eval(funcstring)

then optionally to attach the original code to the function:

func.source = funcstring
cherplunk
  • 85
  • 1
  • 1
  • 5
    The use of eval() strikes me as being really, REALLY bad, unless you're writing some kind of interactive Python interpreter. Eval opens up drastic security problems. If you adopt a policy of only eval'ing string literals, you still lose out on a variety of helpful behavior, ranging from syntax highlighting to proper reflection of classes which contain eval'ed members. – Mark E. Haase May 23 '12 at 14:38
  • 2
    Upvoting. @mehaase: security is obviously not an issue here. Your other comments though are quite relevant, though I'd say lack of syntax highlighting is a combination of the fault of the IDE and the fact that python is not a homoiconic language. – ninjagecko Aug 16 '12 at 22:59
  • 12
    @ninjagecko Security is always an issue when you're giving advice to the general public. Most readers are coming here because they are googling questions. I don't think many people are going to copy this answer verbatim; instead, they are going to take the concept they learned and apply it to their own problem. – Mark E. Haase Aug 17 '12 at 19:57
  • @MarkE.Haase you're right that security is always an issue to be mindful of, but there are definitely valid use-cases for `eval` (or it wouldn't be in the spec). The `attrs` library [uses eval](https://github.com/python-attrs/attrs/blob/fcb7393f53f12a80ff9fcf931b0d16686ed98c58/src/attr/_make.py#L315-L320) to build customized dunder methods for classes. Not eval-ing user input solves the vast majority of relevant security concerns. Still, not something to trifle with. – mtoor Sep 01 '21 at 00:59
3

Rafał Dowgird's answer states:

I believe that if the function is compiled from a string, stream or imported from a compiled file, then you cannot retrieve its source code.

However, it is possible to retrieve the source code of a function compiled from a string, provided that the compiling code also added an entry to the linecache.cache dict:

import linecache
import inspect

script = '''
def add_nums(a, b):
    return a + b
'''

bytecode = compile(script, 'unique_filename', 'exec')
tmp = {}
eval(bytecode, {}, tmp)
add_nums = tmp["add_nums"]

linecache.cache['unique_filename'] = (
    len(script),
    None,
    script.splitlines(True),
    'unique_filename',
)

print(inspect.getsource(add_nums))

# prints:
# """
# def add_nums(a, b):
#    return a + b
# """

This is how the attrs library creates various methods for classes automatically, given a set of attributes that the class expects to be initialized with. See their source code here. As the source explains, this is a feature primarily intended to enable debuggers such as PDB to step through the code.

mtoor
  • 218
  • 2
  • 7
0

If all the previous excellent methods fail you are still stuck (!!), you can try to crash your function and use traceback to get at least some of the code.

In [1]: import traceback
   ...: def foo(arg1,arg2):
   ...:     #do something with args
   ...:     a = arg1 + arg2
   ...:     return a
   ...: 

In [2]: try:
   ...:     foo(None, None)
   ...: except Exception as e:
   ...:     print(repr(e))
   ...:     print(traceback.format_exc())
   ...: 
TypeError("unsupported operand type(s) for +: 'NoneType' and 'NoneType'")
Traceback (most recent call last):
  File "<ipython-input-2-5e7289999181>", line 2, in <module>
    foo(None, None)
  File "<ipython-input-1-db29b8b8f18d>", line 4, in foo
    a = arg1 + arg2
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'

Might need to get creative and does not work if the func has no parameters.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
HeyWatchThis
  • 21,241
  • 6
  • 33
  • 41
-2
from dis import show_code
show_code(XXX)
TPArrow
  • 1,518
  • 18
  • 25
  • 2
    A simple example of a function and a sample output would be helpful, because `show_code` doesn't actually show the _source code_ of user-defined functions and completely fails for builtin functions. – Gino Mempin May 21 '23 at 03:26
-7

I believe that variable names aren't stored in pyc/pyd/pyo files, so you can not retrieve the exact code lines if you don't have source files.

Abgan
  • 3,696
  • 22
  • 31