如何简化Python代码(来自书本的作业)?

2024-06-01 09:50:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在学习查尔斯R.塞弗伦斯写的书,我对第七章的练习2有个问题。你知道吗

任务是遍历mbox-short.txt文件并“当遇到以X-DSPAM-Confidence开头的行时:”拉开该行以提取该行上的浮点数。对这些行进行计数,然后计算这些行的垃圾邮件可信度值的总和。当到达文件末尾时,打印出垃圾邮件的平均置信度。“

以下是我完成这项任务的方法:

fname = input('Enter the file name: ') 
try:
    fhand = open(fname) 
except:
    print('File cannot be opened:', fname)
    exit()
count = 0
values = list()
for line in fhand:
    if line.startswith('X-DSPAM-Confidence:'): 
        string = line
        count = count + 1
        colpos = string.find(":")
        portion = string[colpos+1:]
        portion = float(portion)
        values.append(portion)   
print('Average spam confidence:', sum(values)/count)

我知道这段代码是有效的,因为我得到了与书中相同的结果,但是,我认为这段代码可以更简单。我之所以这么认为是因为我在代码中使用了一个列表(声明了它,然后在其中存储了值)。然而,“列表”是书中的下一个主题,当解决这个任务时,我对列表一无所知,不得不用谷歌搜索它们。我以这种方式解决了这个任务,因为这是我在R语言中要做的(我已经非常熟悉了),我会制作一个向量,在其中存储迭代中的值。你知道吗

所以我的问题是:这个代码可以简化吗?我可以不使用list做同样的任务吗?如果是,我怎么做?你知道吗


Tags: 文件代码列表stringcountline垃圾邮件fname
3条回答

您可以在循环之前过滤文件的行,然后将其他变量折叠为一个变量,并使用列表理解获取值。从这一点上,你就可以从那张单子的长度中得到你的计数。你知道吗

interesting_lines = (line.startswith('X-DSPAM-Confidence:') for line in fhand)
values = [float(line[(line.find(":")+1):]) for line in interesting_lines]
count = len(values)

Can I do the same task without using list?

如果输出需要是平均值,那么可以将总和和计数累加为它们自己的变量,而不需要调用sum(values)的列表

请注意,open(fname)无论如何都会给您一个iterable集合,并且您会在文件中的“行列表”上循环。你知道吗

我可以将“values”对象更改为浮动类型。这个问题实际上并不需要列表的开销。你知道吗

values = 0.0

然后在循环中使用

values += portion 

否则,真的没有一个更简单的方法,因为这个问题有任务,你必须满足所有的任务才能解决它。你知道吗

  1. 打开文件
  2. 检查错误
  3. 环行
  4. 查找特定行
  5. 总上说行
  6. 打印平均值

如果你能用3行代码就可以了,那就太好了,但这并不能让后台的工作变得简单。它也可能看起来很丑。你知道吗

列表理解通常可以替换添加到列表中的循环:

fname = input('Enter the file name: ') 
try:
    fhand = open(fname) 
except:
    print('File cannot be opened:', fname)
    exit()

values = [float(l[l.find(":")+1:]) for l in fhand if l.startswith('X-DSPAM-Confidence:')]

print('Average spam confidence:', sum(values)/len(values))

内部部分只是您的代码组合,因此可读性可能较低。你知道吗

编辑:不使用列表,可以使用“reduce”进行编辑:

from functools import reduce
fname = input('Enter the file name: ') 
try:
    fhand = open(fname) 
except:
    print('File cannot be opened:', fname)
    exit()

sum, count = reduce(lambda acc, l: (acc[0] + float(l[l.find(":")+1:]), acc[1]+1) if l.startswith('X-DSPAM-Confidence:') else acc, fhand, (0,0))

print('Average spam confidence:', sum / count)

Reduce在其他语言中通常称为“fold”,它基本上允许您使用“累加器”对集合进行迭代。这里,我使用一个累加器来迭代集合,累加器是(sum, count)的元组。对于每一项,我们将其相加并递增计数。见Reduce documentation。你知道吗

尽管如此,“简化”并不一定意味着尽可能少的代码,所以如果您对这些速记符号不满意,我将坚持使用您自己的代码。你知道吗

相关问题 更多 >