0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Python]リストのコピーとfor文

Posted at

目的

この記事を閲覧して,以下のことが分かる事

  • list のコピー時の挙動
  • シャローコピーとディープコピー
  • for 文中の list の挙動

list のコピー

まずはこちらを考えてみましょう.

Q.以下のコードを実行した場合,どのように出力されるでしょうか?

a = [0, 1, 2, 3]
b = a # b に a をコピー
a.append(4) # a に 4 を追加

print(a)
print(b)

選択肢 A

[0, 1, 2, 3, 4]
[0, 1, 2, 3]

選択肢 B

[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]

A. 選択肢 B
答えは選択肢 B です.

a にだけ 4 を追加したのに何故 b にも 4 が追加されているの?
こう思いませんでしたか?
これ実は,a と b が同じリストになってしまっています.

print(id(a)) # 135764862582848
print(id(b)) # 135764862582848

つまり,a のコピーとして別の b を用意したつもりが,
実はどっちも同じリストだったということになります.
では,どうすれば a のコピーとして別の b を用意できるのか.以下で解説いたします.

copy

copyをインポートすることで解決できます.
いったんこちらをご覧ください.

import copy
a = [0, 1, 2, 3]
b = copy.copy(a)
a.append(4)

print(a) # [0, 1, 2, 3, 4]
print(id(a)) # 13576486259635
print(b) # [0, 1, 2, 3]
print(id(b)) # 135764862644352

copy を使うことで,a と別のコピー b を用意することができました.
これで a に 4 を追加しても,b には 4 が追加されません.

シャローコピーとディープコピー

上記の通り,copyを使えば思い通りのコピーができそうだという事がわかりました.
しかし,コピーには

  • シャローコピー(浅いコピー)
  • ディープコピー(深いコピー)

というものがあります.厄介ですね..

ということでいったんこちらをご覧ください.

import copy
a = [0, 1, 2, 3, [100, 110]]
b = a
c = copy.copy(a) # シャローコピー
d = copy.deepcopy(a) # ディープコピー
a[3] = 4
a[4][0] = 777

print(f"a: {a}, id: {id(a)}, id(a[4]): {id(a[4])}")
print(f"b: {b}, id: {id(b)}, id(b[4]): {id(b[4])}")
print(f"c: {c}, id: {id(c)}, id(c[4]): {id(c[4])}")
print(f"d: {d}, id: {id(d)}, id(d[4]): {id(d[4])}")

出力

a: [0, 1, 2, 4, [777, 110]], id: 135764861728000, id(a[4]): 135764861728448
b: [0, 1, 2, 4, [777, 110]], id: 135764861728000, id(b[4]): 135764861728448
c: [0, 1, 2, 3, [777, 110]], id: 135764861720192, id(c[4]): 135764861728448
d: [0, 1, 2, 3, [100, 110]], id: 135764861724480, id(d[4]): 135764861719744

ざっくり解説

シャローコピー:
新しいコピーを作成する(要素内のリストなどは a と同じところを指す)
リスト内のリストなど深いところまではコピーしない(浅い)

ディープコピー:
完全に新しいコピーを作成する
リスト内のリストなど深いところまでコピーする(深い)

ここまでのまとめ

  • a と同じリストを作るときは a = b
  • a のコピーを新しく作成し,その後 a と異なる操作をしたい時は copy を使う
  • a のコピーで完全に新しいリストを作成したい時はディープコピーする

for 文中のリスト

for 文でリストの要素分ループさせる時,
ループ中にそのリストに要素を追加したらどうなるでしょうか?
最初にループが始まった時の要素分だけでループ?
追加されたらその分追加でループされる?

ということでこちらをご覧ください.

list_a = [0, 1, 2, 3]

for i, a in enumerate(list_a):
  print(a)
  list_a.append(a+100)
  if i >= 6:
    break

print(list_a)

出力

0
1
2
3
100
101
102
[0, 1, 2, 3, 100, 101, 102, 103, 200, 201, 202]

答えは,ループ中に追加した分まで追加でループされるでした.

まとめ

  • a と同じリストを作るときは a = b
  • a のコピーを新しく作成し,その後 a と異なる操作をしたい時は copy を使う
  • a のコピーで完全に新しいリストを作成したい時はディープコピーする
  • リストのループ中に要素を追加したら,その追加分まで追加でループする
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?