2017-06-21 5 views
1

リストで2次元配列を初期化する必要があります。たとえば、2X3アレイの場合
[[0,0,0], [0,0,0]]Pythonで2dリストを初期化すると値間のリンクが得られます(同じアドレス)

最初の試みは:

In: a1 = [[0]*3]*2 
In: a1[0][0] = 100 
In: a1 
Out: [[100,0,0], [100,0,0]] 

これは奇妙です。だから私はチェックした:

In: a1 = [[0]*3]*2 
In: id(a1[0][0]) 
Out: 4518461984 
In: id(a1[1][0]) 
Out: 4518461984 

同じアドレス。

第二の試み:

In: a2 =[[0]*3 for i in range(2)] 
In: a2[0][0] = 100 
In: a2 
Out: [[100, 0, 0], [0, 0, 0]] 

右。

は、私は再びメモリアドレスを確認してみましょう:

In: a2 =[[0]*3 for i in range(2)] 
In: id(a2[0][0]) 
Out: 4518461984 
In: id(a2[1][0]) 
Out: 4518461984 

まあ、奇妙な。もう一度同じアドレス。私は異なる住所を期待していた。私の最初の推測では、返されるアドレスは値へのポインタのアドレスです。それでは、どのようにしてスロットのアドレスを取得できますか?

この現象を引き起こしたPythonの動作を説明できる人はいますか? Pythonでは、どちらがポインタで、どれが値であるかを知ることは非常に難しいと思います。

+0

私はそれを読んだことがありますが、使用している*や範囲に応じてコピーが生成されるためです。 –

+0

@Coldspeedのこのコメントは私の質問を解決しました。 '注釈として、変更可能な構造体で*を使用すると、それらの参照も同様に再利用されることに注意してください。 - Coldspeed' –

答えて

1

表現[v] * n「は外側のリストにnvへの参照を追加」と等価です。

これは、常にfがリテラルであることの罰金です:

a = [1] * 4 
id(a[0]) == id(a[2]) # True 

a[0] = 15     
print(a)    # a == [15, 1, 1, 1] 

しかし、同じメカニズムがfが可変であるために適用されます。 fへの参照は、n回挿入されます。

a = [ [1, 2, 3] ] * 3 

あなたがaの任意の要素を変更する場合、それらはすべて同じリストへの参照であることから、他のすべてはまた、変更されます。

a[0][0] = 2 
print(a)  # [[2, 2, 3], [2, 2, 3], [2, 2, 3]] 

あなたはcommon sequence operations上のドキュメントを読むことによって、この動作についての詳細を学ぶことができます。

多次元リストを作成するための提案方法は、次のとおり

n = 5 
mda = [[0] * 3 for _ in range(5)] 

これは、新しいリスト・インスタンスが作成され、その後、外側のリストに追加され、ループの各反復において、動作します。

2

あなたのリストのアドレスではなく、リストの値のメモリアドレスを比較しています。

あなたのリストのメモリアドレスが異なります

>>> a2 =[[0]*3 for i in range(2)] 
>>> id(a2[0]) == id(a2[1]) # compare memory addresses of the sublists 
False 

しかし、あなたの最初の例では「サブ」のリストは同じです:

>>> a1 = [[0]*3]*2  
>>> id(a1[0]) == id(a1[1]) 
True 

値が同じメモリアドレスが持っている理由質問複雑:

  • Pythonは-5から255の整数を再利用します(CPython at least)ので、0は常に同じメモリアドレスを持ちます。それらは、( - 多分も同じモジュール - またはしない機能で同一「行」内で同じ機能で使用される)同じブロックで定義されている場合10000

    >>> a = 0 
    >>> b = 0 
    >>> a is b 
    True 
    
  • リテラル番号は、同じメモリアドレスを有します。

    >>> a = 5000 
    >>> b = 5000 
    >>> a is b # different "lines" and not in a function! 
    False 
    
    >>> a, b = 5000, 5000 
    >>> a is b # defined on the same "line" 
    True 
    
  • あなたは参照が再利用されているlistを掛けます。この場合、それは文字通りの数字なので重要ではないので、参照は常に再利用されます。しかし、場合には、それは重要かもしれないリテラルの数ではありません:あなたのケースでは

    >>> l = [int('1000')]*3 
    >>> l[0] is l[1] 
    True 
    
    >>> l = [int('1000') for _ in range(3)] 
    >>> l[0] is l[1] 
    False 
    

あなたは、同じ行の数を定義し、それらが常に同じメモリアドレスを持つことになりますので、それは小さな整数です。Pythonで

+2

追加可能な注釈として、変更可能な構造体とともに*を使用すると、それらの参照も同様に再利用されることに注意してください。 –

+0

@Coldspeedそれは正しいですが、それは各サブリストに影響します。第1のサブリスト内の第1の番号が第2のサブリスト内の第1の番号と同じIDを有する理由は、「小さな整数キャッシュ」のためである。 – MSeifert

関連する問題