4

Pythonで実行中のイテレータのドメインスペースを削除しても安全かどうか(文書化された動作?)を知りたいと思いました。

コードを考えてみましょう:

import os
import sys

sampleSpace = [ x*x for x in range( 7 ) ]

print sampleSpace

for dx in sampleSpace:

    print str( dx )

    if dx == 1:

        del sampleSpace[ 1 ]
        del sampleSpace[ 3 ]

    elif dx == 25:

        del sampleSpace[ -1 ]

print sampleSpace

「sampleSpace」は、私が「イテレータのドメイン空間」と呼んでいるものです(より適切な単語/フレーズがある場合は、lemme know)。

私がやっていることは、イテレータ'dx'が実行されている間に値を削除することです。

これが私がコードに期待することです:

Iteration versus element being pointed to (*):

0: [*0, 1, 4, 9, 16, 25, 36]
1: [0, *1, 4, 9, 16, 25, 36] ( delete 2nd and 5th element after this iteration )
2: [0, 4, *9, 25, 36]
3: [0, 4, 9, *25, 36] ( delete -1th element after this iteration )
4: [0, 4, 9, 25*] ( as the iterator points to nothing/end of list, the loop terminates )

..そしてこれが私が得るものです:

[0, 1, 4, 9, 16, 25, 36]
0
1
9
25
[0, 4, 9, 25]

ご覧のとおり、私が期待しているのは私が得たものです。これは、このようなシナリオで他の言語から得た動作は逆です。

したがって、Pythonで「反復中にスペースを変更するとイテレータが無効になる」などのルールがあるかどうかを尋ねたいと思います。

Pythonでこのようなことをするのは安全ですか(文書化された動作?)?

4

3 に答える 3

6

Pythonチュートリアルから:

ループ内で繰り返されるシーケンスを変更することは安全ではありません(これは、リストなどの可変シーケンスタイプでのみ発生する可能性があります)。繰り返し処理するリストを変更する必要がある場合(たとえば、選択したアイテムを複製するため)、コピーを繰り返し処理する必要があります。スライス表記はこれを特に便利にします:

>>> for x in a[:]: # make a slice copy of the entire list
...    if len(x) > 6: a.insert(0, x)
...
>>> a
['defenestrate', 'cat', 'window', 'defenestrate']
于 2010-06-03T11:34:29.167 に答える
1

一般的に言えば、それは安全ではなく、予測できない動作をする可能性があります。このような状況では、イテレータは特定の方法で動作する必要はありません。

あなたの例で何が起こっているのか

# list is [0, 1, 4, 9, 16, 25, 36]

if dx == 1:
    # we're at index 1 when this is true
    del sampleSpace[ 1 ]
    # we've removed the item at index 1, and the iterator will move to the next valid position - still index 1, but in a mutated list. We got lucky in this case
    # the list now contains [0, 4, 9, 16, 25, 36]
    del sampleSpace[ 3 ]   
    # we remove the item at index 3 which is (now) value 16
    # the list now contains [0, 4, 9, 25, 36]
elif dx == 25:

    del sampleSpace[ -1 ]
    # we remove the final item, list now looks like
    # the list now contains [0, 4, 9, 25]
于 2010-06-03T11:34:58.073 に答える
0

安全とはどういう意味ですか?あなたのコードはたまたまエラーを発生させませんが、もちろんそれは明確な可能性です、これを考慮してください:

>>> a = range(3)
>>> for i in a:
    del a


Traceback (most recent call last):
  File "<pyshell#13>", line 2, in <module>
    del a
NameError: name 'a' is not defined
>>> a
[0, 1, 2]
>>> for i in a:
    del a[i+1]


Traceback (most recent call last):
  File "<pyshell#27>", line 2, in <module>
    del a[i+1]
IndexError: list assignment index out of range

なぜこれを実行するのかは明確ではありませんが、イテレータに適用できる追加のルールはありません。それらは他のタイプとまったく同じように動作しています。

于 2010-06-03T11:23:47.820 に答える