Skip to main content
 首页 » 编程设计

python之为什么我不能拆分这个 python 列表

2025年05月04日15kuangbin

我有一些代码来解析 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 清空再次缓冲。