Python 用dropwhile()和takewhile()过滤状态,dropwhile()
和takewhile()
是有状态的过滤函数:从一种模式开始,当满足给定的谓词函数时切换到另一模式。dropwhile()
函数开始采用拒绝模式,当谓词函数变为False
时切换为通过模式。takewhile()
则从通过模式开始,当谓词函数变为False
时切换到拒绝模式。二者都是过滤器,所以会处理整个可迭代对象。
可以利用这些函数过滤掉输入文件的头部和尾部。首先用dropwhile()
过滤掉文件头部的文本行,返回剩余的数据,然后用takewhile()
保留数据部分,去掉文件尾部的文本行。回到第前面的GPL文件格式,文件头部如下所示:
GIMP Palette
Name: Crayola
Columns: 16
#
其后的文本行如下所示:
255 73 108 Radical Red
基于dropwhile()
函数,可以方便地定位到文件头部的最后一行,即#
这一行,如下所示:
with open("crayola.gpl") as source:
rdr = csv.reader(source, delimiter='\t')
rows = dropwhile(lambda row: row[0] != '#', rdr)
之前创建了CSV reader基于Tab字符解析文本行,可以方便地将名称和颜色三元组分开,之后进一步解析三元组,就可得到#
行之后处理文件剩余内容的迭代器了。
可以使用islice()
函数去掉可迭代对象的第一项,然后解析颜色的细节,如下所示:
color_rows = islice(rows, 1, None)
colors = (
(color.split(), name) for color, name in color_rows
)
print(list(colors))
表达式islice(rows, 1, None)
与rows[1:]
这样的切片表达式类似,会丢弃第一项。一旦移除头部的文本行,就可以解析颜色元组并返回更有用的颜色对象了。
就该文件而言,还可以通过CSV reader解析出的列数实现文本过滤,例如使用dropwhile(lambda row: len(row) == 1, rdr)
方法也可以过滤掉文件头部,但这种方法并不普适,通常通过定位头部最后一行比通过一些文本特征区别文件头和数据更容易。本例中文件头部是通过列数识别出来的,属于个例。