2

Python の奇妙な動作を見つけました (または、属性の継承やデフォルト値がどのように機能するかを理解していない可能性があります)。

指定されたコードについて

class A(object):
    def __init__(self, s):
        self.s = s
        print "in init", self.s

class B(A):
    def __init__(self, s = set()):
        super(B, self).__init__(s)
        print "after super", self.s
        self.s.add('foo')
        print '--------------'

if __name__ == "__main__":
    a = B()
    b = B()

次の出力が得られます。

in init set([])
after super set([])
--------------
in init set(['foo']) # Why it has value set in other object?!
after super set(['foo'])
--------------

もちろん、望ましい動作は、2 番目のオブジェクト (b) の self.s を空のセットで初期化することですが、理由は不明ですが、前のオブジェクトから状態を取得します。なぜそれが起こるのですか?望ましい動作を取得する方法は?

ありがとう!

4

2 に答える 2

8

ミュータブルなデフォルト引数の罠にはまってしまいました。set()B でデフォルトとして指定したは、作成__init__する各 new に渡される同じオブジェクトBです。に入れてselfも新しいコピーは作成されず、同じオブジェクトへの参照が作成されるだけです。

おそらく、新しいオブジェクトごとにコピーを作成したいので、明示的に行います。

class A(object):
    def __init__(self, s):
        self.s = copy.copy(s)
于 2013-03-11T16:22:17.137 に答える
0

引数のデフォルトを設定すると、関数を呼び出すときではなく、関数を定義するときに値が計算されます。したがって、set()クラスを定義したときに作成されたものと同じものを使用し、それにどんどん項目を追加しています。

代わりに、典型的な Python パターンはNone、デフォルトとして を使用してから、 の本体内で新しいset()(またはリスト、辞書、または任意のオブジェクト) を明示的に初期化することです__init__

class B(A):
  def __init__(self, s=None):
    if s is None:
      s = set()
于 2013-03-11T16:33:00.483 に答える