Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a Python function's source code without the definition lines

Using the inspect.getsourcelines function, I have been able to get a Python function's source code like this:

import inspect    

def some_decorator(x):
    return x

@some_decorator
def foo():
    print("bar")

print(inspect.getsourcelines(foo)[0])

This code will correctly output the source lines of the function as a list:

['@some_decorator\n', 'def foo():\n', '    print("bar")\n']

However, I only want the code inside the function, not the entire function declaration. So I only want this output (noting also the correct indentation):

['print("bar")\n']

I have attempted to do this using a slice and a strip to remove the first two lines and then remove indentation, but this wouldn't work with many functions and I have to believe there's a better way.

Does the inspect module, or another module which I can pip install, have this functionality?

like image 715
Aaron Christiansen Avatar asked Oct 22 '25 05:10

Aaron Christiansen


2 Answers

The two solutions in the accepted answer break if the definition takes more than one line and annotations are used (since annotations introduce extra ":"). In the following I take care of that case too (but not the async case contained in the accepted answer's second function.

import inspect
from itertools import dropwhile


def get_function_body(func):
    source_lines = inspect.getsourcelines(func)[0]
    source_lines = dropwhile(lambda x: x.startswith('@'), source_lines)
    line = next(source_lines).strip()
    if not line.startswith('def '):
        return line.rsplit(':')[-1].strip()
    elif not line.endswith(':'):
        for line in source_lines:
            line = line.strip()
            if line.endswith(':'):
                break
    # Handle functions that are not one-liners  
    first_line = next(source_lines)
    # Find the indentation of the first line    
    indentation = len(first_line) - len(first_line.lstrip())
    return ''.join([first_line[indentation:]] + [line[indentation:] for line in source_lines])

For example, applied to:

# A pre comment
def f(a, b: str, c='hello', 
      d: float=0.0, *args, **kwargs) -> str:
    """The docs"""
    return f"{c} {b}: {a + d}"

print(get_function_body(f))

I get

"""The docs"""
return f"{c} {b}: {a + d}"
like image 79
thorwhalen Avatar answered Oct 24 '25 19:10

thorwhalen


You can find that the code you want all have blank before, so you can try this

print filter(lambda x:x.startswith(' '), inspect.getsourcelines(foo)[0])
like image 44
Daoctor Avatar answered Oct 24 '25 19:10

Daoctor