python计算代码_Python代码统计工具

Python代码统计工具

标签: Python 代码统计

声明

本文将对《Python实现C代码统计工具(一)~(三)》中的C代码统计工具进行扩展,以支持Python脚本自身的行数统计。

一. 问题提出

此前实现的C代码统计工具仅能分析和统计C语言代码文件,但其设计思想也适用于Python代码及其他编码语言。

Python行数统计的难点在于注释行,因为Python有两种注释方式:简单明了的单行注释和复杂含糊的多行注释(块注释)。单行注释以#(pound或hash)符号起始,直至物理行的末尾(但字符串内的#并无注释作用)。多行注释可在每行头部添加#号,也可包入未命名的三引号字符串(triple-quoted strings,即多行字符串)内。除非未命名三引号字符串作为对象的文档字符串(docstring),即模块、类、或函数体的第一条语句为未命名字符串,否则可作为多行注释。

下面以总27_代7_注15_空5.py脚本为例,演示不同的注释方式。注意,该脚本仅作测试数据用,并非真实世界中的脚本文件。

#!/usr/bin/python

# -*- coding: utf-8 -*-

#comment3

print 'code1'

'''comment4

print """comment5"""

comment6'''

"""comment7

'''print 'comment8 and comment9'

"""

print 'code2'

def code3():

"""f = open('whatever', 'r')

multiline comment 10,11,12 make up a doc string

"""

print 'code4'

'''

print 'comment13, comment14 and comment15'

'''

return 'code5'

help(code3); print 'code6'

print code3.__doc__, 'code7'

运行该脚本后,输出如下:

code1

code2

Help on function code3 in module __main__:

code3()

f = open('whatever', 'r')

multiline comment 10,11,12 make up a doc string

code6

f = open('whatever', 'r')

multiline comment 10,11,12 make up a doc string

code7

使用未命名三引号字符串做注释时,存在如下缺点:

未命名字符串本质上并非注释,而是不生成字节码的语句。因此,需要满足缩进要求(常错点)。

无法注释掉已包含相同三引号字符串的代码。

IDE的语法高亮会将三引号字符串标记为字符串,而不是注释区。

此外,大多数IDE均支持选择代码片段,并自动使用单行注释符对选区添加注释。以IDLE(Python GUI)为例,快捷键Alt+3可添加注释,Alt+4可删除注释。因此,建议总是使用#号添加多行注释,而三引号字符串仅用于调试过程中临时性地注释代码块。

二. 代码实现

为同时支持统计C和Python代码,需对CalcLines()和CountFileLines()函数稍作修改。其他函数实现参考C代码统计工具前述系列文章。可以看出,绝大部分实现只需少量或无需修改,这表明前期的函数划分和布局得当。

为求直观,将原先的CalcLines()函数重命名为CalcLinesCh()。接着,实现统计Python脚本行信息的CalcLinesPy()函数:

def CalcLinesPy(line, isBlockComment):

#isBlockComment[single quotes, double quotes]

lineType, lineLen = 0, len(line)

line = line + '\n\n' #添加两个字符防止iChar+2时越界

iChar, isLineComment = 0, False

while iChar < lineLen:

#行结束符(Windows:\r\n; MacOS 9:\r; OS X&Unix:\n)

#不可写为"if line[iChar] in os.linesep"(文件可能来自异种系统)

if line[iChar] == '\r' or line[iChar] == '\n':

break

elif line[iChar] == ' ' or line[iChar] == '\t': #空白字符

iChar += 1; continue

elif line[iChar] == '#': #行注释

isLineComment = True

lineType |= 2

elif line[iChar:iChar+3] == "'''": #单引号块注释

if isBlockComment[0] or isBlockComment[1]:

isBlockComment[0] = False

else:

isBlockComment[0] = True

lineType |= 2; iChar += 2

elif line[iChar:iChar+3] == '"""': #双引号块注释

if isBlockComment[0] or isBlockComment[1]:

isBlockComment[1] = False

else:

isBlockComment[1] = True

lineType |= 2; iChar += 2

else:

if isLineComment or isBlockComment[0] or isBlockComment[1]:

lineType |= 2

else:

lineType |= 1

iChar += 1

return lineType #Bitmap:0空行,1代码,2注释,3代码和注释

相应地,CountFileLines()函数作如下修改:

def CountFileLines(filePath, isRawReport=True, isShortName=False):

fileExt = os.path.splitext(filePath)

if fileExt[1] == '.c' or fileExt[1] == '.h':

CalcLinesFunc = CalcLinesCh

elif fileExt[1] == '.py':

CalcLinesFunc = CalcLinesPy

else:

return

isBlockComment = [False]*2 #或定义为全局变量,以保存上次值

lineCountInfo = [0]*4 #[代码总行数, 代码行数, 注释行数, 空白行数]

with open(filePath, 'r') as file:

for line in file:

lineType = CalcLinesFunc(line, isBlockComment)

lineCountInfo[0] += 1

if lineType == 0: lineCountInfo[3] += 1

elif lineType == 1: lineCountInfo[1] += 1

elif lineType == 2: lineCountInfo[2] += 1

elif lineType == 3: lineCountInfo[1] += 1; lineCountInfo[2] += 1

else:

assert False, 'Unexpected lineType: %d(0~3)!' %lineType

if isRawReport:

global rawCountInfo

rawCountInfo[:-1] = [x+y for x,y in zip(rawCountInfo[:-1], lineCountInfo)]

rawCountInfo[-1] += 1

elif isShortName:

detailCountInfo.append([os.path.basename(filePath), lineCountInfo])

else:

detailCountInfo.append([filePath, lineCountInfo])

CountFileLines()函数根据后缀判断文件类型并调用相应的统计函数,并扩展isBlockComment列表以存储两种Python块注释(三单引号和三双引号)。除此之外,别无其他修改。

三. 效果验证

将本文的统计实现命名为PCLineCounter.py。首先,混合统计C文件和Python脚本:

E:\PyTest>PCLineCounter.py -d lctest

FileLines CodeLines CommentLines EmptyLines CommentPercent FileName

6 3 4 0 0.57 E:\PyTest\lctest\hard.c

33 19 15 4 0.44 E:\PyTest\lctest\line.c

243 162 26 60 0.14 E:\PyTest\lctest\subdir\CLineCounter.py

44 34 3 7 0.08 E:\PyTest\lctest\subdir\test.c

44 34 3 7 0.08 E:\PyTest\lctest\test.c

27 7 15 5 0.68 E:\PyTest\lctest\总27_代7_注15_空5.py

------------------------------------------------------------------------------------------

397 259 66 83 0.20

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值