使用Python ast库统计.py文件函数代码行数时出现计数不全问题
问题:ast库统计函数代码行数异常
用Python的ast库解析mathQuiz.py统计函数代码行数时,仅前两个函数统计结果正常,draw_question及之后的函数行数统计明显错误。
统计代码(lineCount.py)
import ast def get_function_info(file_path): with open(file_path, 'r') as f: tree = ast.parse(f.read()) functions = [node for node in tree.body if isinstance(node, ast.FunctionDef)] function_info = [] for function in functions: function_name = function.name function_line_count = function.body[-1].lineno - function.body[0].lineno + 1 function_info.append((function_name, function_line_count)) print(len(functions)) print(function_info) return len(functions), function_info get_function_info('mathQuiz.py')
目标文件(mathQuiz.py)
import turtle import random import math def draw_square(): turtle.penup() turtle.forward(100) turtle.pendown() turtle.forward(50) turtle.left(90) turtle.forward(25) turtle.left(90) turtle.forward(50) turtle.left(90) turtle.forward(25) turtle.left(90) def generate_question(): operators = ['+', '-', '*', '/'] questions = set() while len(questions) < 5 * 3: operator = random.choice(operators) if operator == "+": a = random.randint(0, 99) b = random.randint(0, 99 - a) result = a + b elif operator == "-": a = random.randint(1, 99) b = random.randint(1, a) result = a - b elif operator == "*": a = random.randint(1, math.floor(math.sqrt(99))) b = random.randint(1, math.floor(math.sqrt(99))) result = a * b else: result = random.randint(1, math.floor(math.sqrt(99))) b = random.randint(1, math.floor(math.sqrt(result))) a = result * b question = f'{a} {operator} {b} = ' if question not in questions: questions.add(f'{question}{result}') return questions def draw_question(questions): turtle.penup() turtle.goto(-200, 200) turtle.pendown() for i, question in enumerate(questions): turtle.write(question, font=('Arial', 16, 'normal')) draw_square() if i % 3 == 2: turtle.penup() turtle.goto(-200, turtle.ycor() - 50) turtle.pendown() else: turtle.penup() turtle.goto(turtle.xcor() + 75, turtle.ycor()) turtle.pendown() def draw_answer(questions): turtle.penup() turtle.goto(-200, -100) turtle.pendown() for i, question in enumerate(questions): turtle.write(question, font=('Arial', 16, 'normal')) draw_square() if i % 3 == 2: turtle.penup() turtle.goto(-200, turtle.ycor() - 50) turtle.pendown() else: turtle.penup() turtle.goto(turtle.xcor() + 75, turtle.ycor()) turtle.pendown() def put_answer(answers): turtle.penup() turtle.goto(-100, -100) turtle.pendown() for i, answer in enumerate(answers): turtle.write(answer, font=('Arial', 16, 'normal')) if i % 3 == 2: turtle.penup() turtle.goto(-100, turtle.ycor() - 50) turtle.pendown() else: turtle.penup() turtle.goto(turtle.xcor() + 175, turtle.ycor()) turtle.pendown() turtle.hideturtle() turtle.speed(0) turtle.penup() turtle.goto(-250, 250) turtle.write("Quiz", font=("Arial", 24, "normal")) turtle.pendown() turtle.forward(100) questions = generate_question() questions_without_answer = [question.split('=')[0] + ' = ' for question in questions] draw_question(questions_without_answer) turtle.penup() turtle.goto(-250, -50) turtle.write("Answer", font=("Arial", 24, "normal")) turtle.pendown() turtle.forward(100) draw_answer(questions_without_answer) answers = [question.split('=')[1] for question in questions] put_answer(answers) turtle.done()
问题原因
原代码通过function.body[-1].lineno - function.body[0].lineno + 1计算行数,仅当函数体最后一个元素是单行语句时有效。如果函数体末尾是复合语句(比如for循环、if分支),function.body[-1].lineno取的是该复合语句的起始行号,而非结束行号,导致统计结果偏小。
修复方案
Python 3.8及以上的ast节点提供end_lineno属性,可直接获取函数的结束行号。修改统计逻辑,用函数自身的起止行号计算:
import ast def get_function_info(file_path): with open(file_path, 'r') as f: tree = ast.parse(f.read()) functions = [node for node in tree.body if isinstance(node, ast.FunctionDef)] function_info = [] for function in functions: function_name = function.name # 统计函数体行数(不含def行) function_line_count = function.end_lineno - function.lineno # 若要包含def行,改为:function.end_lineno - function.lineno + 1 function_info.append((function_name, function_line_count)) print(len(functions)) print(function_info) return len(functions), function_info get_function_info('mathQuiz.py')
运行修复后的代码,会输出所有函数的正确行数:
draw_square: 9generate_question: 22draw_question: 11draw_answer: 11put_answer: 9
内容的提问来源于stack exchange,提问作者Xiao Lin
相关产品推荐
相关产品推荐

