Help us understand the problem. What is going on with this article?

回り道Python(1)

More than 1 year has passed since last update.

リストのコピーにハマる

Pythonでリストの複製を行おうと思って以下のようなコードを書いてハマる。

wrong1.py
sequence = [2, 3, 5, 7, 11, 13]
subsequence = sequence
subsequence.remove(13)
print(sequence)
print(subsequence)

期待していた実行結果は

[2, 3, 5, 7, 11, 13]
[2, 3, 5, 7, 11]

なのだが、実際の結果は

[2, 3, 5, 7, 11]
[2, 3, 5, 7, 11]

ハテ? removeしたsubsequenceの方はともかく、なんでsequenceまで要素13が削除が削除されたの?

理由が分からなくて調べるとすぐに判明。subsequence = sequenceというのが誤りで、これだとsubsequenceのIDをsequenceのIDで上書きしてしまう。つまり、subsequenceが指し示しているものと、sequenceが指し示しているものが、同一のものになるのだそうだ。だから、subsequenceにsequenceのコピーを作って内容を書き換えたつもりだったが、sequenceの内容そのものを書き換えていたのだ。

この辺は、C言語のポインタで出てくるような話に似ている。関数呼び出しの場合に参照渡し(アドレス渡し?ポインタ渡し?)すると呼び出し元の変数にアクセスできるようになるものだ。swap()関数のようなものをCで書く場合に良く例として挙げられるものだ。

ちなみに、上のPythonコードを期待通りに動作させる場合は、リストのIDをコピーするのではなく各要素をコピーするようにスライス[:]を付けてあげると良いのだそうだ。

correct1.py
sequence = [2, 3, 5, 7, 11, 13]
subsequence = sequence[:]
subsequence.remove(13)
print(sequence)
print(subsequence)

ただし、このコピー操作はとても遅いのか、数万個要素のリストコピーを数万回のループで処理させていたらとても時間がかかっていたのに、その分を見直して削除したら途端に早くなった。長い系列処理で、こういうコードを繰り返し実行するのは避けるべきだ。

Takeru_MIYAZAKI
Dr. Eng. / Engineering Adviser (EA) at the Univ. of Kitakyushu / Pseudorandom Number Generator / Sequence / Cryptography / Biometrics / Numeric Theory
https://twitter.com/Takeru_MIYAZAKI
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away