0

ここのジュニア python プログラマーであり、予想外の for ループと辞書の動作にレンガの壁に頭をぶつけてきました。ログエントリの CSV ファイルをループして、データを解析してカテゴリ辞書にします。ループのたびにカテゴリ 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 を一度初期化する必要があります。

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

ただし、カテゴリ 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の原則に違反していると確信していますが、何をどのように見つけるべきかわかりません。問題がカテゴリ辞書に関連していることを理解するのに何時間もかかりました。

どんな説明にも大いに感謝します。

4

1 に答える 1

2

あなたが使用しているツールには詳しくありませんが、ループの外側で辞書を作成すると、1 つの辞書が作成されるだけです。

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 に答える