私はバグレポートを提出する前に大胆な意見を述べる前に、賢明なPythonistの私の前提をここで確認したいと思っていました。今日は不可解なケースに遭遇したので、私は、以下に示す、おもちゃの例にそれを絞り込ま:Python関数の呼び出しがスコープを出血している、ステートフルで、パラメータの初期化に失敗しましたか?
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
A little script to demonstrate that a function won't re-initialize its
list parameters between calls, but instead allows them to retain state.
"""
def bleedscope(a=[], b=[]):
"""
On each call, unless explicitly passed, both `a` and `b` should be
initialized as empty lists.
"""
c = a
if b:
c.extend(b)
return len(c)
x = bleedscope(b=[1])
print x # Should be 1, as expected.
x = bleedscope(b=[2])
print x # Expect also to be 1, but it's 2. `a` is retained.
x = bleedscope(a=[1])
print x # Now 1 as expected.
x = bleedscope(b=[3])
print x # 1 as expected? No, it's 3! Insanity!
私は、関数の引数は、関数へのスコープ内のローカルだと思っていたし、関数の最後にガベージコレクトされましたそれらの間に状態を保持することは決してありません。私は上記のスクリプトをPython 2.5.2とPython 2.6.1でテストしましたが、私の理解は結果ではありません。引数a
は、これらの呼び出しのほとんどの間に確実に状態を保持します。最も複雑なものは、bleedscope
への最終コールであり、前のコールの状態をスキップし、2番目のコールの状態(すなわち、[1, 2]
)に戻る。 [自分の好きなデバッガでこれを実行して、自分自身で確認することをお勧めします。お持ちでない場合は、私は固体FOSSスタンドアロンPythonのデバッガとしてWinpdbを示唆している。]
ここで何が起こっていますか?
任意の変更可能なオブジェクトは、デフォルト値のために悪い選択です - 変更可能なオブジェクト(リストなど)はこの方法では使用できません。 –