1
  1 import sys
  2 
  3 class dummy(object):
  4     def __init__(self, val):
  5         self.val = val
  6 
  7 class myobj(object):
  8     def __init__(self, resources):
  9         self._resources = resources
 10 
 11 class ext(myobj):
 12     def __init__(self, resources=[]):
 13         #myobj.__init__(self, resources)
 14         self._resources = resources
 15 
 16 one = ext()
 17 one._resources.append(1)
 18 two = ext()
 19 
 20 print one._resources
 21 print two._resources
 22 
 23 sys.exit(0)

これにより、とオブジェクトone._resourcesの両方に割り当てられたオブジェクトへの参照が出力されます。オブジェクトの作成時に定義されていない場合は、明らかにそのように設定されているため、空の配列になると思います。コメントを外しても同じことが起こります。を使用しても同じことができます。onetwotwomyobj.__init__(self, resources)super(ext, self).__init__(resources)

それを機能させる唯一の方法は、次を使用する場合です。

two = ext(dummy(2))

これを機能させるために、オブジェクトを作成するときにデフォルト値を手動で設定する必要はありません。または多分私はそうします。何かご意見は?

Python 2.5および2.6を使用してこれを試しました。

4

5 に答える 5

7

あなたは変わるべきです

def __init__(self, resources=[]):
    self._resources = resources

def __init__(self, resources=None):
    if resources is None:
        resources = []
    self._resources = resources

そしてすべてが良くなります。これは、デフォルトの引数が変更可能である場合の処理​​方法の詳細です。このページのディスカッション セクションには、さらに詳しい情報があります。

于 2009-10-07T21:51:46.733 に答える
6

あなたの問題は、関数の定義時にデフォルト値が評価されることです。これは、同じリスト オブジェクトがインスタンス間で共有されることを意味します。詳細については、この質問への回答を参照してください。

于 2009-10-07T21:51:54.720 に答える
2

からクラスをセットアップする方法については、この回答をお読みください__init__()。Python のよく知られた癖に遭遇しました: ミュータブルをセットアップしようとしていますが、ミュータブル__init__()はコンパイル時に 1 回評価されます。標準的な回避策は次のとおりです。

class ext(myobj):
    def __init__(self, resources=None):
        if resources is None:
            resources = []
        #myobj.__init__(self, resources)
        self._resources = resources
于 2009-10-07T21:55:07.763 に答える
1

http://docs.python.org/3.1/tutorial/controlflow.htmlから:

デフォルト値は一度だけ評価されます。デフォルトがリスト、辞書、またはほとんどのクラスのインスタンスなどの可変オブジェクトである場合、これは違いを生みます。

于 2009-10-07T21:52:40.353 に答える
0

これは既知のPythonの落とし穴です。

関数/メソッドの呼び出しで可変オブジェクトを使用することは避けなければなりません。

デフォルト値を提供するオブジェクトは、関数/メソッドが呼び出された時点では作成されませんこれらは、関数を定義するステートメントが実行されるときに作成されます。(Pythonのデフォルト引数の説明を参照してください:2つの簡単な失敗「デフォルト引数の式は、関数が呼び出されたときではなく、定義されたときに計算されます。」

この動作は、Python言語ではいぼではありません。これは実際には機能であり、バグではありません。可変のデフォルト引数を本当に使用したい場合があります。たとえば、彼らができることの1つは、以前の呼び出しの結果のリストを保持することです。これは非常に便利な場合があります。

しかし、ほとんどのプログラマー、特にPythonistaを始めたばかりのプログラマーにとって、この振る舞いは落とし穴です。したがって、ほとんどの場合、次のルールを採用しています。

  • 引数のデフォルト値として、可変オブジェクト(つまり、リスト、ディクショナリ、またはクラスインスタンス)を使用しないでください。
  • ルール1を無視するのは、自分が何をしているかを本当に、本当に、本当に知っている場合のみです。

だから...私たちは常にルール#1に従うことを計画しています。さて、問題はそれをどのように行うかです...私たちが望む振る舞いを得るためにfunctionFをどのようにコーディングするかです。

幸いなことに、解決策は簡単です。デフォルトとして使用される可変オブジェクトはに置き換えられNone、引数は。に対してテストされNoneます。


では、どうすればそれを正しく行うことができますか?1つの解決策は、引数に可変のデフォルト値を使用しないようにすることです。しかし、新しいリストが便利なデフォルトであることがあるため、これはほとんど満足のいくものではありません。すべての引数をディープコピーする関数のデコレータを定義するなど、いくつかの複雑なソリューションがあります。これはやり過ぎであり、問​​題は次のように簡単に解決できます。

class ext(myobj):
    def __init__(self, resources=None):
        if not resources:
            resources = []
        self._resources = resources
于 2009-10-07T22:08:08.127 に答える