0

这里是初级 python 程序员,我一直在为意外的循环和字典行为撞墙。我正在遍历日志条目的 CSV 文件并将数据解析为类别字典。当我每次通过循环初始化类别字典时,它按预期工作..

像这样:

log_entries = AutoVivification()
# http://stackoverflow.com/questions/635483/what-is-the-best-way-to-implement-nested-dictionaries-in-python

def scrublooper(log_file):

    for ll in log_file:
    # Initialize  categories dict every round through the loop
    categories = {'requests': {'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 0, 'Pages': 0, 'Content_Files': 0}, 'filter_action': {'re': 0, 'pl': 0, 'bs': 0}}
    lld = LogDomain(ll)
    domain, hostname, lan_host = lld.domain, lld.hostname, lld.lan_host


    mimetypes = url_searcher(Settings.mimetypes, lld.mime_type)

    if mimetypes:
        category = mimetypes[2]

        if not log_entries[lan_host].has_key(domain): 
            log_entries[lan_host][domain]= categories

        log_entries[lan_host][domain]['requests'][category] += 1 

print log_entries['192.168.5.210']['google.com']['requests']
print log_entries['192.168.5.210']['webtrendslive.com']['requests']
print log_entries['192.168.5.210']['osnews.com']['requests']
print log_entries['192.168.5.210']['question-defense.com']['requests']
print log_entries['192.168.5.210']['optimost.com']['requests']

这种外观的输出是我所期望的:

{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 95, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 1, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 2, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 18, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 3, 'Pages': 0, 'Content_Files': 0}

然而!这是我的问题。我不想每次都通过循环初始化类别字典。在这个简化的示例案例中,这无关紧要,但在这个程序的道路上,它会导致显着的性能下降 (30%)。

我需要初始化类别字典一次:

log_entries = AutoVivification()
categories = {'requests': {'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 0, 'Pages': 0, 'Content_Files': 0}, 'filter_action': {'re': 0, 'pl': 0, 'bs': 0}}

def scrublooper(log_file):

    for ll in log_file:
    lld = LogDomain(ll)
    # etc, etc, etc

但是,当我在 for 循环之外初始化类别字典 ANYWHERE 时(无论是在scrublooper 函数中还是在log_entries 变量之后),输出为:

{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 685, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 685, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 685, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 685, 'Pages': 0, 'Content_Files': 0}
{'Content_Visual': 0, 'Content_ProgramsUpdates': 0, 'Content_Text': 685, 'Pages': 0, 'Content_Files': 0}

所有 'Conent_Text' 值都相等地增加了!这里发生了什么?我确定我违反了一些 python 原则,但不知道如何找出答案。我花了几个小时才弄清楚问题与类别字典有关。

非常有义务做出任何解释。

4

1 回答 1

2

我不熟悉您使用的工具,但是当您在循环之外创建字典时,您只是在创建一个字典。

if not log_entries[lan_host].has_key(domain): 
        log_entries[lan_host][domain]= categories

这段代码只是让 log_entries[lan_host][domain] 指向那个字典。Python 不会复制这些值或类似的东西。所以这些行指的是同一个字典。

log_entries['192.168.5.210']['google.com']
log_entries['192.168.5.210']['webtrendslive.com']

PS我不能肯定地说,但我的直觉说不想初始化一个新的字典来提高性能可能是过分的。

于 2012-06-05T15:12:10.427 回答