問題のコードの簡略版は次のとおりです。
class thing:
def __init__(self, data1, data2={'foo': 1}):
self.data2 = data2
self.data2['bar'] = data1
datas = ['FIRST', 'SECOND']
things = [thing(x) for x in datas]
for p in things:
print p.data2['bar']
私はこのコードが戻ることを期待します:
FIRST
SECOND
ただし、実際には次の値が返されます。
SECOND
SECOND
どうして?
私の最善の推測は:
ur_dict = {'foo': 1}
、thing
私はいない新しい辞書を作成するself.data2={'foo': 1}
のではなくへの参照を初期化しur_dict
、bar: data1
をself.data2
に追加すると、実際にはそのキーと値がur_dict
それ自体に追加されます。これによりdata2
、リスト内のすべてのオブジェクトのフィールドが更新されます。上記のコードに次のスニペットを追加して、この仮説をテストしました。
things[0].data2['bar'] = 'FIRST'
for p in things:
print p.data2['bar']
案の定、結果は次のとおりです。
FIRST
FIRST
ですから、私の仮説はおそらく正しいと思いますが、それでも私には不思議です。私の質問はこの質問に非常に関連しているようです---コンストラクターでデフォルト値を作成するとき、この値はインスタンス変数ではなくクラス変数ですか?Pythonがオブジェクトの引数のデフォルト値に対して新しいオブジェクトを作成しないのはなぜですか?将来、この種のエラーを概念化またはキャッチするための良い方法はありますか?ここで何が起こっているかについて学ぶためのいくつかの良い参考資料は何ですか?
(専門用語を壊した場合は事前にお詫びします。私は正式な教育を受けた数学者です。)
編集:@CrazyPython[::-1]
これは関数のプロパティであり、クラスやオブジェクトではないと述べました。可変のデフォルト引数を持つ関数の例を作成し、上記のオブジェクトとクラスで経験した方法で関数を壊す方法を見つけようとしています。これを思いついた:
EXPONENT = 1
def fooBar(x, y=EXPONENT):
return x**y
print EXPONENT
print foo(5)
EXPONENT = 2
print EXPONENT
print foo(5)
ただし、次の値が返されます。
1
5
2
5
ここで変更可能なデフォルト引数を使用しない理由を説明するために、これを「破る」良い方法は何ですか?
self.data2={'foo': 1}
変更可能なデフォルト引数です。絶対にしないでください。99%の確率でそれは間違いです。
def foo(a, b={}):
...
と同等ではありません
def foo(a, b=None):
if b is None:
b = {}
b
毎回再構築されるわけではありません。それは同じオブジェクトです。
将来、この種のエラーを概念化またはキャッチするための良い方法はありますか?
PyCharmまたは別の優れたエディターを使用する
コンストラクターでデフォルト値を作成するとき、この値はインスタンス変数ではなくクラス変数ですか?
いやいやいやいやいや。これは、クラスやインスタンスではなく、関数に関連付けられています。これは、すべての機能に適用される動作です。クラスやリンクされた質問とは何の関係もありません。
Pythonがオブジェクトの引数のデフォルト値に対して新しいオブジェクトを作成しないのはなぜですか?
パフォーマンスと互換性。オブジェクトの構築は、潜在的にコストのかかる操作です。
を継承していませんobject
。それは良くないね。*
このPythonコードがリスト内のすべてのオブジェクトのフィールドを変更するのはなぜですか?
文脈がなければ、それは悪いタイトルです。コードについて尋ねます。タイトルを読んだとき、コードはありません。
関数が指定されると、デフォルトの引数が評価されます。(実行されたときではなく、記述されたとき)それらは関数に関連付けられています。関数が実行されると、デフォルトの引数のコピーは作成されません。デフォルトの引数を直接変更します。呼び出される次の関数は、変更を加えた同じオブジェクトを受け取ります。
※あなたは教授等のようです。ミームに腹を立てないでください。それはインターネットからアドバイスを得るリスクです。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加