跳过标题行的更多pythonic方式

puf*_*ish 9 python

是否有更短(或许更pythonic)的方式打开文本文件并读取以注释字符开头的行?

换句话说,这是一种更简洁的方式

fin = open("data.txt")
line = fin.readline()
while line.startswith("#"):
    line = fin.readline()
Run Code Online (Sandbox Code Playgroud)

Rob*_*ney 16

在我学习Python的这个阶段,我发现这个最Pythonic:

def iscomment(s):
   return s.startswith('#')

from itertools import dropwhile
with open(filename, 'r') as f:
    for line in dropwhile(iscomment, f):
       # do something with line
Run Code Online (Sandbox Code Playgroud)

跳过文件顶部的所有行开头#.要跳过所有以下行开头的行#:

from itertools import ifilterfalse
with open(filename, 'r') as f:
    for line in ifilterfalse(iscomment, f):
       # do something with line
Run Code Online (Sandbox Code Playgroud)

这几乎都是关于我的可读性; 功能上几乎没有区别:

for line in ifilterfalse(iscomment, f))
Run Code Online (Sandbox Code Playgroud)

for line in (x for x in f if not x.startswith('#'))
Run Code Online (Sandbox Code Playgroud)

将测试分解为自己的功能使得代码的意图更加清晰; 它还意味着,如果您对评论的定义发生了变化,您就有一个地方可以更改它.


Sil*_*ost 14

for line in open('data.txt'):
    if line.startswith('#'):
        continue
    # work with line
Run Code Online (Sandbox Code Playgroud)

当然,如果您的注释行仅位于文件的开头,则可以使用一些优化.


eph*_*ent 10

from itertools import dropwhile
for line in dropwhile(lambda line: line.startswith('#'), file('data.txt')):
    pass
Run Code Online (Sandbox Code Playgroud)


Wim*_*Wim 6

如果要过滤掉所有注释行(不仅仅是文件开头的注释行):

for line in file("data.txt"):
  if not line.startswith("#"):
    # process line
Run Code Online (Sandbox Code Playgroud)

如果你只想在开始时跳过那些,那么请看看ephemient的答案itertools.dropwhile


Wer*_*sey 5

你可以使用生成器功能

def readlines(filename):
    fin = open(filename)
    for line in fin:
        if not line.startswith("#"):
            yield line
Run Code Online (Sandbox Code Playgroud)

并使用它

for line in readlines("data.txt"):
    # do things
    pass
Run Code Online (Sandbox Code Playgroud)

根据文件的确切位置,您可能还需要检查strip()前的行startswith().我曾经不得不在编写脚本后几个月调试脚本,因为有人在'#'之前插入了几个空格字符


Jim*_*nis 5

作为一个实际的问题,如果我知道我正在处理合理大小的文本文件(任何将舒适地适合内存),那么我的问题是:

f = open("data.txt")
lines = [ x for x in f.readlines() if x[0] != "#" ]
Run Code Online (Sandbox Code Playgroud)

...在整个文件中进行snarf并过滤掉以octothorpe开头的所有行.

正如其他人指出的那样,人们可能希望忽略在octothorpe之前出现的前导空格,如下所示:

lines = [ x for x in f.readlines() if not x.lstrip().startswith("#") ]
Run Code Online (Sandbox Code Playgroud)

我喜欢这个简洁.

这假设我们想要删除所有注释行.

我们还可以使用以下方法"删除"每个字符的末尾(几乎总是换行符):

lines = [ x[:-1] for x in ... ]
Run Code Online (Sandbox Code Playgroud)

...假设我们并不担心文件最后一行丢失的最终换行符的臭名昭着的问题.(唯一一次来自.readlines()或相关的类文件对象方法的行可能不在换行符中结束是EOF).

在最近的Python版本中,可以使用条件表达式从行的末尾"扼杀"(仅新行),如下所示:

lines = [ x[:-1] if x[-1]=='\n' else x for x in ... ]
Run Code Online (Sandbox Code Playgroud)

...这就像我为了清晰易读而列出清单一样复杂.

如果我们担心过大的文件(或低内存限制)可能会影响我们的性能或稳定性,并且我们正在使用最近足以支持生成器表达式的Python版本(这是最近添加的语言而不是我一直在这里使用的列表理解),然后我们可以使用:

for line in (x[:-1] if x[-1]=='\n' else x for x in
  f.readlines() if x.lstrip().startswith('#')):

    # do stuff with each line
Run Code Online (Sandbox Code Playgroud)

...在我们检查代码后一年内,我希望其他任何人在一行中解析.

如果意图只是跳过"标题"行,那么我认为最好的方法是:

f = open('data.txt')
for line in f:
    if line.lstrip().startswith('#'):
        continue
Run Code Online (Sandbox Code Playgroud)

......并完成它.