试试这个:
def code_metric(file_name):
with open(file_name) as f:
lines = [line.rstrip() for line in f.readlines()]
nonblanklines = [line for line in lines if line]
return len(nonblanklines), sum(len(line) for line in nonblanklines)
例子:
>>> code_metric('collatz.py')
(73, 2856)
>>> code_metric('cmtest.py')
(3, 85)
讨论
我只能通过删除行尾的尾随换行符和尾随空格来实现collatz.py 的预期结果。这是在这一步完成的:
lines = [line.rstrip() for line in f.readlines()]
下一步是删除空行:
nonblanklines = [line for line in lines if line]
我们要返回非空行的数量:
len(nonblanklines)
我们还想返回非空行的字符总数:
sum(len(line) for line in nonblanklines)
大文件的替代版本
此版本不需要一次将文件全部保存在内存中:
def code_metric2(file_name):
with open(file_name) as f:
lengths = [len(line) for line in (line.rstrip() for line in f.readlines()) if line]
return len(lengths), sum(lengths)
使用reduce 的替代版本
Python 的创建者 Guido van Rossum,wrote this 关于 reduce 内置函数:
所以现在减少()。这其实是我一直最讨厌的,
因为,除了一些涉及 + 或 * 的例子之外,几乎每次
我看到一个带有非平凡函数参数的 reduce() 调用,我需要
拿起笔和纸,画出实际输入的内容
在我理解 reduce() 应该做什么之前,函数。所以
在我看来,reduce() 的适用性几乎仅限于
关联运算符,在所有其他情况下最好写出
明确的累积循环。
因此reduce 是no longer a builtin in python3。不过,为了兼容性,它在functools 模块中仍然可用。下面的代码如何使用reduce 来解决这个特定问题:
from functools import reduce
def code_metric3(file_name):
with open(file_name) as f:
lengths = [len(line) for line in (line.rstrip() for line in f.readlines()) if line]
return len(lengths), reduce(lambda x, y: x+y, lengths)
这是另一个使用reduce的版本:
from functools import reduce
def code_metric4(file_name):
def fn(prior, line):
nlines, length = prior
line = line.rstrip()
if line:
nlines += 1
length += len(line)
return nlines, length
with open(file_name) as f:
nlines, length = reduce(fn, f.readlines(), (0, 0))
return nlines, length