2009-06-06 2 views
4

私はバグレポートを提出する前に大胆な意見を述べる前に、賢明な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を示唆している。]

ここで何が起こっていますか?

答えて

15

デフォルトのパラメータ値は、def呼び出しが解析されたときにのみ初期化されます。オブジェクト(リストなど)の場合、呼び出し間で再利用されます。また、必要な回避策を提供し、それについてのこの記事を、見てみましょう:

http://effbot.org/zone/default-values.htm

+1

任意の変更可能なオブジェクトは、デフォルト値のために悪い選択です - 変更可能なオブジェクト(リストなど)はこの方法では使用できません。 –

8

これはあなたの問題である:

def bleedscope(a=[], b=[]): 

それは

def bleedscope(a=None, b=None): 
    if a is None: a = [] 
    if b is None: b = [] 

デフォルトパラメータでなければなりません関数が解析されるときに1回だけ実行されるため、毎回同じ2つのリストが使用されます。

1

はFunnily十分に、あなたの入力とあなたの出力は完全に偶発的な理由のために、非常によく似ています。

は実際に何のPythonで起こることは、あなたのメソッド宣言ではaとbのデフォルト値は「静的」な値であるということです。それらはメソッド定義で一度インスタンス化されます。したがって、引数として "a"を渡さないたびにデフォルトの "a"がプッシュされます。

方法の冒頭に「print a」を挿入して確認します。

4

それはFAQです。

+0

更新された[リンク](http://docs.python.org/faq/design.html#why-are-default-values-shared-between-objects) –