令人困惑的魔法行为与dict变量& for Python中的循环

时间:2012-06-05 15:00:37

标签: python

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

像这样:

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}

无论其!这是我的问题。我不希望每次循环都初始化类别dict。在这个简化的示例中,它并不重要,但是在此计划的实施过程中,它将导致性能显着下降(30%)。

我需要初始化类别dict ONCE:

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循环之外初始化类别dict ANWWHERE时(无论是在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原则,但不知道是什么或怎么找出来。我花了几个小时才弄清楚问题与类别字典有关。

很有必要解释。

1 个答案:

答案 0 :(得分: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']

P.S。我不能肯定地说,但我的直觉说不想初始化一本新词典的表现可能是过分的。