乗算オペレータがリストに適用される(データ構造)
-
13-09-2019 - |
質問
私が読んでいる「Pythonプログラミング」の入門テキストですコンピューター科学者のように考える方法ます。
私はリストに適用される乗算演算子(*
)の振る舞いを明確にしたい。
機能を考えるの make_matrix の
def make_matrix(rows, columns):
"""
>>> make_matrix(4, 2)
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> m = make_matrix(4, 2)
>>> m[1][1] = 7
>>> m
[[0, 0], [0, 7], [0, 0], [0, 0]]
"""
return [[0] * columns] * rows
実際の出力である
[[0, 7], [0, 7], [0, 7], [0, 7]]
の make_matrixするの正しいバージョンがある:
def make_matrix(rows, columns):
"""
>>> make_matrix(3, 5)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> make_matrix(4, 2)
[[0, 0], [0, 0], [0, 0], [0, 0]]
>>> m = make_matrix(4, 2)
>>> m[1][1] = 7
>>> m
[[0, 0], [0, 7], [0, 0], [0, 0]]
"""
matrix = []
for row in range(rows):
matrix += [[0] * columns]
return matrix
理由の最初のバージョンの make_matrixする(9.8に本で説明したように)失敗である
...各行は他の行の別名である...
私は疑問に思うなぜ
[[0] * columns] * rows
... ...各行が他の行の別名であるせる
ではなく
[[0] * columns]
すなわち。なぜ行の各[0]
は、他の行の要素の別名ではない。
解決
Pythonですべてがオブジェクトであり、明示的にそうするように頼まない限り、Pythonはコピーを作ることはありません。
あなたが行うと
innerList = [0] * 10
あなたは10個の要素を持つリストを作成し、を同じint
オブジェクトへの参照のうえ、それらのすべてのの0
のの。
整数オブジェクトであるための不変のを、あなたが行うとき、
innerList[1] = 15
それはの15
の別の整数を参照するように、あなたは、リストの2番目の要素を変更しています。それは常にための作品のint
のオブジェクト不変ます。
これは、理由
outerList = innerList * 5
は、それぞれ一つの同じlist
ちょうど上記のようにするへの参照であり、5つの要素を持つinnerList
オブジェクトを作成します。しかしlist
オブジェクトであるため、を変更可能なの
outerList[2].append('something')
と同じです
innerList.append('something')
彼らはを同じlist
オブジェクトのへの2つの参照であるため。だから、要素は、その単一list
で終わります。重複しているように見えるが、実際は一つだけlist
オブジェクトが存在するということであり、それには多くの言及ます。
これとは対照的に、あなたがしなければ、
outerList[1] = outerList[1] + ['something']
ここでは、の(リストをlist
を使用する明示的なコピーである)他 +
オブジェクトの作成、及びouterList
の第2の位置にそれへの参照を割り当てます。あなたはこの方法(実際に追加するが、別のリストを作成していない)の要素を「追加」した場合、innerList
は影響を受けません。
他のヒント
リストは、彼らが参照によって渡され、プリミティブではありません。リストのコピー(C用語で)リストへのポインタです。あなたは浅いコピーを行う場合を除き、あなたがリストにやるものは、リストのすべてのコピーとその内容のコピーに起こります。
[[0] * columns] * rows
おっと、私たちは[0]へのポインタの大きなリストを作りました。 1を変更し、あなたがそれらすべてを変えています。
整数が参照によって渡されていない、彼らは本当にそれゆえ[0] *内容は本当にNEW 0年代の多くを作り、リストに追加され、コピーされます。