2012-06-05 25 views
0

這裏是初級python程序員,我一直在意料之外的循環和字典行爲上擊敗了我的頭。我正在瀏覽日誌條目的CSV文件並將數據解析爲類別字典。當我初始化類通過循環每次快譯通,它按預期工作..用dict變量和for循環在Python中進行混淆魔術行爲

像這樣:

從這個看
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%)。

我需要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 

然而,當我初始化類別ANYWHERE DICT for循環(無論是在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原則,但不知道該怎麼查找。我花了幾個小時才發現問題與類詞典有關。

非常感謝您的任何解釋。

+0

那麼'categories'實際上在哪裏被操縱?我只看到它正在初始化並正在讀取。對於SO來說,你是否簡化了這一點? –

+0

我不認爲它簡化得太過分了。它始終被分配,從不被操縱。分配給'log_entries'字典鍵/值:'如果不是log_entries [lan_host] .has_key(domain):''log_entries [lan_host] [domain] = categories' – Thinkwell

回答

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.我不能肯定地說,但我的直覺說,不想初始化一個新字典的表現可能是過度的。

+0

嗯,嗯,好的...我想要擴展'log_entries [lan_host] [domain]'dict以包含'categories'字典的結構,然後操作'log_entries'實例。我將如何更改代碼來創建該代碼? (Autovivification函數只是在不存在的情況下自動添加鍵,我認爲它添加了'categories'結構而不是引用變量)。 – Thinkwell

+0

好的,當我改變:'log_entries [lan_host] [domain] = categories' To:'log_entries [lan_host] [domain] = {'requests':{'Content_Visual':0,'Content_ProgramsUpdates':0,'Content_Text' :0,'Pages':0,'Content_Files':0},'filter_action':{'re':0,'pl':0,'bs':0}}'然後它就起作用了。所以顯然我的代碼是引用'categories'變量而不是擴展字典。但是,我需要使用變量語法而不是字典。我想我需要嘗試語法來做到這一點。 – Thinkwell

+0

我應該更清楚。如果您在循環內創建字典,它會在每次都會創建一個新的字典。每個log_entries [lan_host] [domain]都是唯一的。這就是爲什麼當你這樣做時你的代碼能夠正常工作。 –