4

重複の可能性:
Pythonの「驚き最小の原則」:可変のデフォルト引数

以下のようなクラスを書こうとすると、かなり奇妙なことがあります。3行目では、引数newdataの新しいコピーをself.dataに配置する必要があります。そうしないと、新しいクラスインスタンスを開始したときに、前のインスタンスの値がクラスに記憶されているように見えます。以下の例を参照して、3行目の2つのバージョンのコードの唯一の違いに注意してください。

class Pt(object):                                                               
    def __init__(self,newdata={}):                                              
        self.data=newdata.copy()                                                       
        if self.data == {}:                                                     
            self._taglist = []                                                  
        else:                                                                   
            self._taglist = self.data.keys()                                    
    def add_tag(self,tag=None):                                                 
        self.data[tag]={'x':[0,1,2,3,4]}                                        
        self._taglist.append(tag)                                               


In [49]: pt = Pt()

In [50]: pt.add_tag('b')

In [51]: pt.add_tag('a')

In [52]: pt.data
Out[52]: {'a': {'x': [0, 1, 2, 3, 4]}, 'b': {'x': [0, 1, 2, 3, 4]}}

In [53]: pt2 = Pt()

In [54]: pt2._taglist
Out[54]: []

class Pt(object):                                                               
    def __init__(self,newdata={}):                                              
        self.data=newdata                                                       
        if self.data == {}:                                                     
            self._taglist = []                                                  
        else:                                                                   
            self._taglist = self.data.keys()                                    
    def add_tag(self,tag=None):                                                 
        self.data[tag]={'x':[0,1,2,3,4]}                                        
        self._taglist.append(tag)                                               

In [56]: pt = Pt()

In [57]: pt.add_tag('a')

In [58]: pt.add_tag('b')

In [59]: pt._taglist
Out[59]: ['a', 'b']

In [60]: pt2 = Pt()

In [61]: pt2._taglist
Out[61]: ['a', 'b']

In [62]: pt2.data
Out[62]: {'a': {'x': [0, 1, 2, 3, 4]}, 'b': {'x': [0, 1, 2, 3, 4]}}

2番目のケースは、newdataとself.dataの両方が同じオブジェクトを参照しているために発生すると思います(ただし、これが発生する可能性がある場合、値は右から左に指定する必要がありますが、逆にしないでください)。したがって、「add_tag」メソッドを使用する場合self.dataを更新するには、newdataも更新されます。それでも、pt2 = Pt()で新しいインスタンスを開始する場合、newdataはデフォルト値({})を使用する必要があると思いますが、それでもpt1から古い値を保持できますか?

4

2 に答える 2

4

理由とすべては、Pythonの「驚き最小の原則:可変デフォルト引数」ですでに非常によく説明されています。だからここにあなたの問題を解決する方法の簡単なヘルプがあります。

デフォルトのパラメータオブジェクトが保持されるため、デフォルトのパラメータ値として可変オブジェクトを使用しないでください。None代わりに、デフォルトのオブジェクトが初期化されるデフォルト値として、通常は固定値を定義する必要があります。したがって、コンストラクターは次のようになります。

def __init__(self, newdata=None):
    if newdata is None:
        newdata = {}
    # ...
于 2012-12-31T17:25:21.097 に答える
1

問題は、辞書をコピーして、同じ値で新しい辞書を作成することです。これは、辞書のリストが同じであることを意味します。したがって、それらを変更すると、すべての辞書でリストが変更されます。

あなたがしたいのはcopy.deepcopy()-これは辞書をコピーするだけでなく、リストもコピーします。

于 2012-12-31T16:30:24.783 に答える