54027


setについて意図と異なる挙動が有り調べても解決できなかったため質問させてください。

このプログラムを実行しますと、

### プログラム

[code]

    d = map(int, [i for i in range(5)])
    print(type(d))
    print(len(set(d)))
    print(type(d))
    print(len(set(d)))
    
[/code]

このような結果が得られます。

### 実行結果

[code]

    <class 'map'>
    5
    <class 'map'>
    0
    <class 'map'>
    
[/code]

### 質問

一回目の`print(len(set(d)))`は5を返します。二回目の`print(len(set(d)))`も同様に5を返す思っていたのですが、0を返してしまう理由を教えていただきたいです。  
一回目と二回目の間で特にdはいじっていないので同じ結果が得られるかなと思っています。  
もしありえるとしたらsetが変数dを破壊的に変更しているとかあるのかなと思ってます。

### 環境

Python 3.7.0

よろしくおねがいします。


CC BY-SA 4.0
2019-04-08T22:38:23.863
54026
2019-04-09T01:12:31.503
32428
question
python python3
Pythonでのsetは破壊的な挙動なのか？


`set` が破壊的なのではなく、ジェネレーターが破壊的なのです。  
map()が返すのはリストではなく、ジェネレーターです。  
ジェネレーターは一度取り出した中身は失われ、次に取り出すものは前回の続きになります。  
このため、 'set(d)' とした時点で、ジェネレーターdの中身がすべて取り出され、次に同じことをしても既にdは空になっています。

[code]

    d = [int(i) for i in range(5)]
    
[/code]

こうやって作った場合、dはリストとして作られるため、何度でも中身を取り出せます。

あるいは以下のように、setの結果を変数に代入しておいてもよいでしょう。

[code]

    d = map(int, [i for i in range(5)])
    s = set(d)  # ここでdは空になる
    print(len(s))
    print(len(s))
    
[/code]


CC BY-SA 4.0
2019-04-08T22:57:30.450
54027
2019-04-09T01:12:31.503
2019-04-09T01:12:31.503
754
806
54026
answer