如何使用python只用一行代码来识别一个函数

时间:2013-10-03 11:46:19

标签: python parsing

我的目标是确定一行的方法/功能。例如,在scenario.py中有两个函数,它们只有一行代码。我的工作是我有一个大型应用程序,我将解析该应用程序中的所有python文件并识别具有一行的函数。

#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

3 个答案:

答案 0 :(得分:9)

使用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)

打印

2
4

注意

如果代码中存在语法错误,则此代码将引发SyntaxError。此外,如果您尝试使用 Python 2 解析 Python 3 代码(反之亦然),则可能会引发SyntaxError(并非总是)。

更新

以上for语句应替换为以下内容:

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)

否则,以下函数被视为oneliner:

def func():
    if True:
        pass

答案 1 :(得分:1)

这是一种适用于“实时”Python函数的方法。请注意,这是特定于CPython的。

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

这会忽略docstrings并仅计算函数的主体。定义与def(或lambda)在同一行上的主体的函数被认为有0行。

不忽略文档字符串的版本更简单:

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

我的原始代码被严重破坏;它统计了陈述而不是行。在我的辩护中,我把它写在了我的头顶并错误地记录了lnotab的细节。

请注意,在Python 3中,不需要转换为bytearray(因为co_lnotab已经bytes),但这样做会使代码同时适用于Python 2.x,其中{ {1}}是co_lnotab(我认为 2.6,后来有str)和3.x。

答案 2 :(得分:-1)

使用inspect和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)