13

新しいスタイルのクラスのサブクラス化と辞書の更新に関する奇妙な問題を発見しました。

Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on
win32
>>> class a(object):
...     def __init__(self, props={}):
...             self.props = props
...
>>> class b(a):
...     def __init__(self, val = None):
...             super(b, self).__init__()
...             self.props.update({'arg': val})
...
>>> class c(b):
...     def __init__(self, val):
...             super(c, self).__init__(val)
...
>>> b_inst = b(2)
>>> b_inst.props
{'arg': 2}
>>> c_inst = c(3)
>>> c_inst.props
{'arg': 3}
>>> b_inst.props
{'arg': 3}
>>>

デバッグでは、2 回目の呼び出し ( ) で、コンストラクター内が既に と等しいc(3)ことがわかります。その後、コンストラクターが呼び出されると、両方のオブジェクトになります。aself.props{'arg': 2}b{'arg': 3}

また、コンストラクターの呼び出し順序は次のとおりです。

  a, b    # for b(2)
  c, a, b # for c(3)

コンストラクター内で置き換えるself.props.update()と、すべてが正常になり、期待どおりに動作しますself.props = {'arg': val}b

しかし、このプロパティを置き換えるのではなく、更新する必要があります。

4

3 に答える 3

17

propsそのようなデフォルト値を持つべきではありません。代わりにこれを行います:

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props

これは一般的な python の"落とし穴"です。

于 2009-09-02T14:06:48.063 に答える
8

あなたの問題はこの行にあります:

def __init__(self, props={}):

{} は変更可能な型です。Python では、デフォルトの引数値は一度だけ評価されます。これは、すべてのインスタンスが同じディクショナリ オブジェクトを共有していることを意味します。

これを修正するには、次のように変更します。

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props
于 2009-09-02T14:06:30.310 に答える
3

短いバージョン: 次のようにします。

class a(object):
    def __init__(self, props=None):
        self.props = props if props is not None else {}

class b(a):
    def __init__(self, val = None):
        super(b, self).__init__()
        self.props.update({'arg': val})

class c(b):
    def __init__(self, val):
    super(c, self).__init__(val)

長いバージョン:

関数定義は 1 回だけ評価されるため、呼び出すたびに同じデフォルト引数が使用されます。これが期待どおりに機能するには、関数が呼び出されるたびにデフォルトの引数を評価する必要があります。しかし、代わりにPythonは関数オブジェクトを一度生成し、デフォルトをオブジェクトに追加します( as func_obj.func_defaults

于 2009-09-02T14:08:43.163 に答える