我有一些代码来解析 apache 日志文件(start_search 和 end_search 是在 apache 日志中找到的格式的日期字符串):
with open("/var/log/apache2/access.log",'r') as log:
from itertools import takewhile, dropwhile
s_log = dropwhile(lambda L: start_search not in L, log)
e_log = takewhile(lambda L: end_search not in L, s_log)
query = [line for line in e_log if re.search(r'GET /(.+veggies|.+fruits)',line)]
import csv
query_dict = csv.DictReader(query,fieldnames=('ip','na-1','na-2','time', 'zone', 'url', 'refer', 'client'),quotechar='"',delimiter=" ")
import re
veggies = [ x for x in query_dict if re.search('veggies',x['url']) ]
fruits = [ x for x in query_dict if re.search('fruits',x['url']) ]
第二个列表生成器总是空的;也就是说,如果我调换最后两行的顺序:
fruits = [ x for x in query_dict if re.search('fruits',x['url']) ]
veggies = [ x for x in query_dict if re.search('veggies',x['url']) ]
第二个列表总是空的。
为什么? (以及如何填充 fruits 和 veggies 列表?)
请您参考如下方法:
你只能循环遍历迭代器一次; query_dict 是一个迭代器,一旦扫描过 veggies 就不能再次迭代以搜索 fruits。
不要在这里使用列表理解。循环遍历 query_dict 一次,检查每个条目中的 veggies 和 fruits:
veggies = []
fruits = []
for x in query_dict:
if re.search('veggies',x['url']):
veggies.append(x)
if re.search('fruits',x['url']):
fruits.append(x)
备选方案是:
为
fruits列表重新创建csv.DictReader()对象:query_dict = csv.DictReader(query,fieldnames=('ip','na-1','na-2','time', 'zone', 'url', 'refer', 'client'),quotechar='"',delimiter=" ") veggies = [ x for x in query_dict if re.search('veggies',x['url']) ] query_dict = csv.DictReader(query,fieldnames=('ip','na-1','na-2','time', 'zone', 'url', 'refer', 'client'),quotechar='"',delimiter=" ") fruits = [ x for x in query_dict if re.search('fruits',x['url']) ]这做了双重工作;您遍历整个数据集两次。
使用
itertools.tee()“克隆”迭代器:from itertools import tee veggies_query_dict, fruits_query_dict = tee(query_dict) veggies = [ x for x in veggies_query_dict if re.search('veggies',x['url']) ] fruits = [ x for x in fruits_query_dict if re.search('fruits',x['url']) ]这最终会将所有
query_dict缓存在tee缓冲区中,同一任务需要两倍的内存,直到fruits清空再次缓冲。
