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?
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}"
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])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With