2017-06-19 4 views
54

このコードはPythonのドキュメントにあります。私は少し混乱しています。Pythonでリストをループして修正する

words = ['cat', 'window', 'defenestrate'] 
for w in words[:]: 
    if len(w) > 6: 
     words.insert(0, w) 
print(words) 

そして、次の私が最初に考えたものである:

words = ['cat', 'window', 'defenestrate'] 
for w in words: 
    if len(w) > 6: 
     words.insert(0, w) 
print(words) 

は、なぜ、このコードは、無限ループを作成しないと、最初のものはないでしょうか?

+1

coz、すべての反復で 'words'リストに要素を挿入しています - )) – marmeladze

+8

最初のものは' words'自体ではなく 'words'のコピーです – depperm

+14

最初は、あなたがそれに記事を追加する前に取った 'words'のコピー。 2番目の方法では、単語をループして同時に単語を長くしようとしているので、決して終わりはありません。 – khelwood

答えて

75

これは問題の1つです!初心者から脱出できるPythonの

words[:]はここでは魔法のソースです。

守っ:[:]なし

>>> words = ['cat', 'window', 'defenestrate'] 
>>> words2 = words[:] 
>>> words2.insert(0, 'hello') 
>>> words2 
['hello', 'cat', 'window', 'defenestrate'] 
>>> words 
['cat', 'window', 'defenestrate'] 

そして今を:

>>> words = ['cat', 'window', 'defenestrate'] 
>>> words2 = words 
>>> words2.insert(0, 'hello') 
>>> words2 
['hello', 'cat', 'window', 'defenestrate'] 
>>> words 
['hello', 'cat', 'window', 'defenestrate'] 

ここで注意すべき主なものは、あなたがコピーを反復処理しているのでwords[:]は、既存のリストのcopyを返すということですこれは変更されません。

あなたはid()を使用して同じリストを参照しているかどうかを確認することができます

最初のケースでは:

>>> words2 = words[:] 
>>> id(words2) 
4360026736 
>>> id(words) 
4360188992 
>>> words2 is words 
False 

後者の場合:

>>> id(words2) 
4360188992 
>>> id(words) 
4360188992 
>>> words2 is words 
True 

それは注目に値しますその[i:j]スライス演算子と呼ばれ、それは新しいtのコピーを返します彼はインデックスiから始まり、インデックス(jまで)をリストアップします。

ので、words[0:2]は最後のインデックスを省略して、開始インデックスが0がデフォルトを意味省略

>>> words[0:2] 
['hello', 'cat'] 

あなたに与えlen(words)にそれをデフォルトを意味し、最終的な結果は、あなたがのコピーを受け取るということです全部リスト


コードを少し読みやすくしたい場合は、copyモジュールをお勧めします。

from copy import copy 

words = ['cat', 'window', 'defenestrate'] 
for w in copy(words): 
    if len(w) > 6: 
     words.insert(0, w) 
print(words) 

これは基本的に最初のコードスニペットと同じことを行い、はるかに読みやすくなります。

(コメントのDSMに記載されているように)また、python> = 3の場合は、同じことを行うwords.copy()を使用することもできます。

+9

@Coldspeed - あなただけの '単語としてそれを書くことができます[:] = [:: - 1] [lenのワットの言葉であれば6>(ワット)のためにW] + words' .... –

+9

ジョンは、私がやりました"より読みやすさ" について、以下...:P –

+0

@Coldspeedより可読性: '言葉[0] = [W言葉で(W)をlenの場合Wの> 6]'。私は、ID() 'オブジェクトがスコープの外に出ると「あなたの場合は特にそうである、解放されたときに番号を再利用することができます'以来、あなたは異なるオブジェクトを持っているかどうかを確認するために、 '()is' ID'上 '使用して強調して推薦する – wizzwizz4

3

は、以下の実施例で

ルック(@Coldspeed応答に加えて):

words = ['cat', 'window', 'defenestrate'] 
words2 = words 
words2 is words 

結果:True

wordwords2が同じオブジェクトを参照する名前を意味します。

words = ['cat', 'window', 'defenestrate'] 
words2 = words[:] 
words2 is words 

結果:この場合False

、私たちは、新しいオブジェクトを作成しました。

10

words[:]は、wordsのすべての要素を新しいリストにコピーします。したがって、words[:]を反復すると、実際にはwordsにあるすべての要素を繰り返し処理しています。あなたがwordsを変更する場合(あなたがwordsを変更するために開始する前にwords[:]に呼び出されているため)ので、これらの変更の影響はwords[:]には表示されません

後者の例では、次のいずれかの変更はあなたが作ることを意味し、wordsを反復処理しています実際にはイテレータにはwordsが表示されます。その結果、wordsのインデックス0に挿入すると、wordsの他のすべての要素が1つのインデックスで「バンプアップ」されます。だから、あなたのfor-loopの次の繰り返しに進むと、次のインデックスwordsで要素を取得しますが、それはあなたが見たばかりの要素です(リストの先頭に要素を挿入したため、他のすべての要素をインデックスで移動します)。イテレータと反復可能オブジェクトを見てみましょう

words = ['cat', 'window', 'defenestrate'] 
for w in words: 
    print("The list is:", words) 
    print("I am looking at this word:", w) 
    if len(w) > 6: 
     print("inserting", w) 
     words.insert(0, w) 
     print("the list now looks like this:", words) 
print(words) 
0

反復可能で返す__iter__メソッドを持つオブジェクトである次のコードを試してみてください、この動作を確認するには

イテレータ、または0から始まる の順次インデックスを使用できる__getitem__メソッドを定義しています( インデックスが有効でなくなったときにはIndexErrorになります)。ですから、反復可能なオブジェクトは、 からイテレータを取得できるオブジェクトです。

反復子はnext(パイソン2)または__next__(パイソン3)メソッドを持つオブジェクトです。

iter(iterable)は反復子オブジェクトを返し、list_obj[:]はlist_objectの完全なコピーである新しいリストオブジェクトを返します。あなたの最初のケースで

for w in words[:] 

forループがリストではありません、元の単語の新しいコピーを反復します。単語の変更はループ反復には影響を与えず、ループは正常終了します。

これは、ループがその作業を行う方法です:

  1. ループはイテレータを返すイテレータと反復する上iterメソッドを呼び出し

  2. ループはイテレータから次の項目を取得するイテレータオブジェクトにnextメソッドを呼び出します。それ以上の要素がStopIteration例外が発生したとき

  3. ループが終了残されていないがあるまで、この工程を繰り返しています。あなたの第2のケースで

:あなたは、元のリストの言葉を反復処理し、言葉に要素を追加している

words = ['cat', 'window', 'defenestrate'] 
for w in words: 
    if len(w) > 6: 
     words.insert(0, w) 
print(words) 

は、イテレータオブジェクトに直接影響を与えます。したがって、単語が更新されるたびに、対応するイテレーターオブジェクトも更新され、無限ループが作成されます。この時

ルック:あなたがStopIteration前に、あなたの元のリストを更新

>>> l = [2, 4, 6, 8] 
>>> i = iter(l) # returns list_iterator object which has next method 
>>> next(i) 
2 
>>> next(i) 
4 
>>> l.insert(2, 'A') 
>>> next(i) 
'A' 

たびに更新されたイテレータを取得し、それに応じてnext戻ります。だからあなたのループは無限に動いているのです。反復とあなたがhereを見ることができ、反復プロトコルの詳細については

関連する問題