LoginSignup
4
3

More than 5 years have passed since last update.

Python3のmap等の生成物(イテレーター)・丸括弧でのジェネレーター内包表記は使い捨て

Last updated at Posted at 2016-04-03

問題のPythonスクリプト(Windows版Python3.5)

from sys import stderr
from copy import copy
N = 5
L1 = list(range(1,N + 1)) #[1,2,3,4,5]
print("L1 =", L1, file = stderr)
L2 = map(lambda i: i ** 2, L1)
L3 = map(lambda i: i ** 2, L1)
L4 = copy(L2)
L5 = [i ** 2 for i in L1]
L6 = list(map(lambda i: i ** 2, L1))
print("L2 =", list(L2)) #[1,4,9,16,25]
print("L2 =", list(L2)) #[1,4,9,16,25]・・・だと思うじゃん???
print("L3 =", list(L3)) #[1,4,9,16,25]
print("L4 =", list(L4)) #[1,4,9,16,25]・・・だと思うじゃん???
print("L5 =", list(L5)) #[1,4,9,16,25]
print("L5 =", list(L5)) #[1,4,9,16,25]
print("L6 =", list(L6)) #[1,4,9,16,25]
print("L6 =", list(L6)) #[1,4,9,16,25]
print("L1 =", L1)

実行結果

L1 = [1, 2, 3, 4, 5]
L2 = [1, 4, 9, 16, 25]
L2 = []
L3 = [1, 4, 9, 16, 25]
L4 = []
L5 = [1, 4, 9, 16, 25]
L5 = [1, 4, 9, 16, 25]
L6 = [1, 4, 9, 16, 25]
L6 = [1, 4, 9, 16, 25]
L1 = [1, 2, 3, 4, 5]

これからわかったこと

これから分かることは、mapで生成したオブジェクトへのアクセスは一度だけ有効である(L2L3)ということです。しかも、copy.copyで浅いコピー(L4)をしても無駄でした。何回もアクセスするときはリスト内包表記を使う(L5、ただし外側は角括弧)か、即座にリストorタプル化(L6)すべきですね。mapオブジェクトの中身をデバッグで表示しなければならない時、このような特性によるデバッグ時のみの原因不明のバグにハマるかもしれません。

コメント欄での指摘がありましたが、丸括弧でジェネレーター内包表記を行うと、map同様使い捨てになります。

mapの使いどき

基本的に生成してからのアクセスを1度だけ(L6のようにリストorタプル化することも含む)にすればL2L4のような事態を回避できます。

他のオブジェクトについて

rangezipなども似たようなオブジェクトを生成しますが、これらも使い捨ての可能性があります。です。(コメントでの指摘より)複数回アクセスする場合はご注意ください。

4
3
7

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
4
3