11

私の友人が次の Python コードを見せてくれました。

a[1:] == a[:-1]

aすべての項目が同一である場合に True を返します。

私は、このコードは一目で理解するのが難しく、さらにa、比較のために のコピーが 2 つ作成されるため、メモリの使用効率が悪いと主張しました。

Python を使用disして、ボンネットの背後で何が起こっているかを確認しましたa[1:]==a[:-1]

>>> def stanga_compare(a):
...     return a[1:]==a[:-1]
...
>>> a=range(10)
>>> stanga_compare(a)
False
>>> a=[0 for i in range(10)]
>>> stanga_compare(a)
True

>>> dis.dis(stanga_compare)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (1)
              6 SLICE+1
              7 LOAD_FAST                0 (a)
             10 LOAD_CONST               2 (-1)
             13 SLICE+2
             14 COMPARE_OP               2 (==)
             17 RETURN_VALUE

それは 2 つのスライス コマンドに要約されます -SLICE+1SLICE+2. ドキュメントは、これらのオペコードが実際に の新しいコピーを作成するのかa、それとも単なる参照を作成するのかについて明確ではありません。

  • SLICE コマンドはコピーしますaか?
  • 答えは Python の実装 (Cython、Jython) によって異なりますか?

アップデート

このスニペットは明らかに判読不能で紛らわしいので、実際のコードで使用するつもりはありません。私の関心は純粋に技術的なものです - スライスがリストをコピーするかどうか、そして答えが状況によって異なるかどうかです。

4

4 に答える 4

3

はい、listオブジェクトを使用すると、Python はスライス時に浅いコピーを作成しますが、ループは C (cpython 用) で作成されるため、同じことを行うために Python で記述できるものよりもはるかに高速になります。浅いコピーのために C で 2 回ループし、比較のために再度ループすると、Python で 1 回ループするよりも高速になります。

多くの場合、cpython は十分に高速ですが、Python コードは C コードよりも約 100 倍遅いことを覚えておいてください。したがって、少し速度が必要な場合は、ループを実行する cpython をそのままにしておく方が一般的には優れています。c = a + bPython のようなものでさえ、多くのロジック (分岐やメモリ割り当てを含む) の実行を意味することに注意してください。

一方、コードにとってこの種のマイクロ最適化が基本的なものである場合、おそらく Python はあなたが戦っている問題に適したツールではなく、他のオプションを検討する必要があります (Cython を使用して、sip とインターフェースをとった小さな C++ 拡張機能を作成するなど)。 PyPy ...)。

訓練を受けていない人にはコードが読めないことを確認し、リストが長く、多くの場合定数ではないall(y == x[0] for y in x)場合、短絡のために高速になります (ループが Python にあり、すべての要素に対して追加の添え字操作が行われる場合でも)。 )。

読みやすさが重要です。多くの。

編集

要素を C コードでループさせるもう 1 つの興味深いオプションは、次のとおりです。

x and x.count(x[0]) == len(x)

これは短絡を提供しませんが、私のPCでは、all1000個の要素のすべてが等しいリストのベースのソリューションよりも約75倍速く、x[1:] == x[:-1].

よりも少し読みやすいと思いますがx[1:] == x[:-1]、おそらく好みの問題です。

于 2013-12-08T07:29:15.210 に答える
0

通常のリストの場合、スライスによってコピーが作成されます。代わりに反復を使用してコピーを防ぐことができます。

import itertools
a1 = iter(a)
a2 = iter(a)
a2.next() # start a2 iterator one removed
all_are_identical = all((i1 == i2 for i1, i2 in itertools.izip(a1, a2)))

この行(i1 == i2 for i1, i2 in itertools.izip(a1, a2))は、 a の各要素が次の要素と等しいかどうかを一度に 1 つずつ返すジェネレータを作成しallます。結果は最初にリストに入れられるのではなく、1 つずつ評価されるため、ある程度のパフォーマンスを犠牲にしてメモリを節約できます。

于 2013-12-08T07:17:16.053 に答える