0

My goal is to identify methods/ functions that are one lines. For example in scenario.py there are two function that has only one line of code written within them. My works is that i have a large application and I will be parsing all the python files in that application and identify function that has one lines.

#Scenario.py
line 1--->  class parent:
line 2--->     def father(self):
line 3--->        print "dad"
line 4--->     def mother(self):
line 5--->        print "mom"

Sample Output:

One liner function at : line=2, line =4
2
  • 1
    Just curious, what is this needed for? There's probably a better solution. Commented Oct 3, 2013 at 12:00
  • Actually i am instrumenting decorators on to the functions that has more than one line and retrieve some dynamic information during runtime Commented Oct 3, 2013 at 12:22

3 Answers 3

9

Using ast:

import ast

def iter_functions(code):
    tree = ast.parse(code)
    for x in tree.body:
        if isinstance(x, ast.FunctionDef):
            yield x
        elif isinstance(x, ast.ClassDef):
            for x in tree.body:
                for y in x.body:
                    yield y

code = r'''class parent:
    def father(self):
        print "dad"
    def mother(self):
        print "mom"
    def grandfather(self):
        print "grand"
        print "dad"
'''

# This is incorrect. See UPDATE
for f in iter_functions(code):
    if len(f.body) > 0 and len({stmt.lineno for stmt in f.body}) == 1:
        print(f.lineno)

prints

2
4

NOTE

If there is a syntax error in the code, this code will raise SyntaxError. Also, if you try to parse Python 3 code with Python 2 (vice versa), it could raise SyntaxError (not always).

UPDATE

Above for statement should be replaced with following:

for f in iter_functions(code):
    if len({node.lineno for stmt in f.body for node in ast.walk(stmt)
            if hasattr(node, 'lineno')}) == 1:
        print(f.lineno)

Otherwise, following function is considered as oneliner:

def func():
    if True:
        pass
Sign up to request clarification or add additional context in comments.

Comments

1

Here's a way that works with "live" Python functions. Note that this is very CPython-specific.

def func(x):
    print(x)

def numlines(func):
    lnotab = bytearray(func.__code__.co_lnotab)
    return sum(lnotab[3::2]) + (bool(lnotab) and min(lnotab[1], 1))

print(numlines(func) < 2)    # True

This ignores docstrings and counts only the body of the function. Functions that define the body on the same line as the def (or are lambda) are considered to have 0 lines.

A version that doesn't ignore docstrings is a bit simpler:

def numlines_including_docstring(func):
    return sum(bytearray(func.__code__.co_lnotab)[1::2])

My original code was badly broken; it counted statements rather than lines. In my defense, I wrote it off the top of my head and misremembered details about lnotab.

Note that in Python 3 the conversion to bytearray is not necessary (since co_lnotab is already bytes) but doing so makes the code work with both Python 2.x, where co_lnotab is a str (I think 2.6 and later have __code__) and 3.x.

2 Comments

If the body of func(x) of is if True: pass (2 lines), oneliner returns True.
Yep yep. Screwed that up. Have hopefully fixed it now. I removed the oneliner() function since it's easy enough to just test numlines(func).
-1

Using inspect and regex:

import re
import inspect
import my_module

for name, func in inspect.getmembers(my_module, predicate=inspect.isfunction):
    func_source = inspect.getsource(func)
    nlines = len(re.findall('\n', func_source))
    print (name, nlines)

1 Comment

myfunc is not defined. Maybe it's func. You should unpack func into name, func. And, this code only handle module level function (not method).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.