2

リストをループすると、ループ内でリストの要素に付ける名前は、次のように各要素を順番に直接参照しているようです。

>>> a = [1, 2, 3]
>>> for n in a:
...     print n is a[a.index(n)]
True
True
True

では、なぜこれは何もしないように見えるのでしょうか?

>>> for n in a: del n
>>> a
[1, 2, 3]

試してみるとdel a[a.index(n)]、奇妙な動作になりますが、少なくともそれは私が理解できる動作です-要素を削除するたびに、リストを短くして他の要素のインデックスを変更するため、リストの他のすべての要素を削除することになります:

>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for n in a: del a[a.index(n)]
>>> a
[1, 3, 5, 7, 9]

明らかに、反復中にリストから削除することが許可されています。del nでは、ループ内に入ろうとすると何が起こっているのでしょうか? 何か削除されていますか?

4

5 に答える 5

7

for n in Xステートメントのブロック内では、「繰り返し処理した最後の値のリスト内の場所」という概念ではなく、それ自体nという名前の変数を参照します。nしたがって、ループが行っていることは、変数nをリストから取得した値に繰り返しバインドし、すぐに同じ変数のバインドを再度解除することです。このdel nステートメントは、リストではなく、ローカル変数バインディングにのみ影響します。

于 2013-11-01T00:27:20.967 に答える
2

あなたはこれをやっているからです:

some_reference = a[0]
del some_reference
#do you expect this to delete a[0]? it doesn't.

の値にバインドされた変数を操作していますa[0](次に、にバインドされた変数a[1]、次に...)。削除することはできますが、何もしませんa

于 2013-11-01T00:32:53.390 に答える
1

他の人は参照を削除するという考え方をかなりうまく説明していますが、完全を期すためにアイテムの削除に触れたかっただけです。同様の構文を使用しても、del a[1]タイプごとに項目の削除の処理が少し異なります。予想どおり、ほとんどのコンテナからアイテムを削除しても、それらが削除されるだけであり、タプルなどの一部のタイプでは、アイテムの削除がまったくサポートされていません。楽しいエクササイザーとして:

class A(object):
    def __delitem__(self, index):
        print 'I will NOT delete item {}!'.format(index)

a = A()
del a[3]
# I will NOT delete item 3!
于 2013-11-01T00:41:25.020 に答える
1

Dolda2000 の回答は主な質問をうまくカバーしていますが、他に 3 つの問題があります。


index(n)ループ内で使用することfor n in aは、ほとんど常に悪い考えです。

それは間違っています:

a = [1, 2, 1, 2]
for n in a:
    print(a.index(n))

これは0、次に1、そして0再び出力されます。なんで?さて、3 番目の値は1です。a.index(1)リストの最初のインデックスです1。それは0、そうではありません2

また、遅い: th の値を見つけるには、リストの最初の要素iをチェックする必要があります。iこれにより、単純な線形 (高速) アルゴリズムが 2 次 (低速) アルゴリズムに変わります。

幸いなことに、Python には、必要なことを正確に行うための優れたツールがありますenumerate

for i, n in enumerate(a):
    print(i)

または、値がまったく必要ない場合は、インデックスのみを使用します。

for i in len(range(a)):
    print(i)

(これは、少なくとも 2 回はドキュメントにヒントとして表示され、初心者が見たことのない場所に便利に埋め込まれています。しかし、チュートリアルの早い段階でも詳しく説明されています。)


次に、Dolda2000 が説明したケースを正確にテストしようとしていたようです。

n is a[a.index(n)]

なぜそれがうまくいかなかったのですか?それらが同じオブジェクトであることを証明したのに、削除しても何も起こらなかったのはなぜですか?

変数が値 (他のアドレスへの参照を含む) が格納されるアドレスである C ファミリ言語とは異なり、Python 変数は、別の場所に独自に存在する値にバインドする名前です。したがって、変数は他の変数を参照できませんが、同じ値の名前にすることはできます。このis式は、2 つの式が同じ値を指定しているかどうかをテストします。つまり、同じ値に対して 2 つの名前があることが証明されました。それらの名前の 1 つを削除しましたが、もう 1 つの名前と値はまだ存在しています。

例は 1000 語の価値があるので、これを実行します。

a = object() # this guarantees us a completely unique value
b = a
print a, b, id(a), id(b), a is b
del b
print a, id(a)

(もちろん、あなたもdel aの場合、ある時点で Pythonは値削除しますが、それを確認することはできません。定義により、それを参照する名前がなくなったためです。)


明らかに、反復中にリストから削除することが許可されています。

そうですね。Python では、反復処理中に iterable を変更した場合に何が起こるかを未定義のままにしていますが、組み込みの可変シーケンス (つまりlist) でfor何が起こるかを説明する特別な言語dictがあります。しかし、それは aRuntimeErrorを上げること保証できないとどこかに言っていRuntimeErrorます。

したがって、それが のサブクラスまたはサードパーティのシーケンス クラスではなく、 であることがわかっている場合は、反復中にそこから削除することでき、削除する要素が at または to の場合は「スキップ」動作を期待できます。イテレータの左。しかし、その知識の現実的な有効活用を考えるのはかなり難しいです。alistlist

于 2013-11-01T23:08:27.987 に答える
0

やるとこうなる

for n in a: del a[a.index(n)]

これを試して:

a = [0, 1, 2, 3, 4]
for n in a: print(n, a); del a[a.index(n)]

これはあなたが得るものです:

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

したがって、n は単なるインデックスのトラッカーであり、このように考えることができます。関数が繰り返されるたびに、 n は iterable 内の次の相対位置に移動します。この場合、n は 1 回目は a[0]、2 回目は a[1]、3 回目は a[2] を参照します。その後、リストに nextItem がないため、反復は停止します。

于 2013-11-01T04:34:11.697 に答える