3

日付が過去の場合 (現在の日付よりも小さい場合) にリスト項目をフィルター処理する機能があります。

meetings = []
def clean_old():
    meetings = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

リストが空の場合、このコードはクラッシュします。

なぜクラッシュするのですか?と表示されfor meeting in meetings、ミーティングが空であれば、すべて問題ありません。

どうすれば修正できますか?また、その発生の説明は何ですか?

4

1 に答える 1

7

この例外が表示されていると思います:

UnboundLocalError: local variable 'meetings' referenced before assignment

ここで経験していることは、実際にはリスト内包表記とは何の関係もありません。このエラーは、最初meetingsに関数の外部で定義したが、関数内で新しい値を割り当てようとしたために発生します。

Python は、関数内で変数に値が割り当てられていることを確認すると、それをその関数に固有の新しい変数として扱います。これにより、関数は、関数の外部から同じ名前を持つ変数にアクセスできなくなります。

内部的には、Python は次のようなことを行っています。

meetings_outside = []

def clean_old():
    meetings_inside = [meeting for meeting in meetings_inside if time.mktime(meeting) >= time.localtime()]

これが失敗する理由は理解できます:meetings_insideはそれ自体で定義されています。Python が の値を検索してmeetings_insideコンテンツの反復処理を開始しようとすると、まだ値が割り当てられていないため失敗します。

これに対処する方法は、使用している Python のバージョンによって異なり、そこで の初期値meetingsが定義されています。

nonlocal meetingsPython 3 では、関数の先頭に単純に追加できます。meetingsこれにより、別の変数を作成するのではなく、という名前の既存の変数を参照していることがわかります。

nonlocalただし、おそらくキーワードを持たない Python 2 を使用しています。同じことを行うglobalキーワードがありmeetingsますが、モジュールのトップレベルで定義されている場合に限ります。つまり、他の関数またはクラスの外側です。

たとえば、ファイルに他に何もない場合、これは Python 2 で機能します。

輸入時間

meetings = []

def clean_old():
    global meetings
    meetings = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

clean_old()
print meetings
[]

meetingsただし、関数内で定義されているため、これはそうではありません。

import time

def main():
    meetings = []

    def clean_old():
        global meetings
        meetings = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

    clean_old()
    print meetings

main()
NameError: global name 'meetings' is not defined

この問題を回避する必要があります。最も簡単な方法は、割り当てを次のように変更することです。

 meetings[:] = [meeting for meeting in meetings if time.mktime(meeting) >= time.localtime()]

meetingsこれは、 内のすべての値を置き換えているが、新しいlistオブジェクトを作成していないことを Python に伝えます。(:構文は「スライシング」と呼ばれ、Python チュートリアル で部分的に説明されています。)

于 2012-11-30T23:06:52.963 に答える