Pythonの組み込み関数の多く(いくつか例を挙げるany()
とall()
、、、sum()
)は反復可能を取りますが、なぜそうではlen()
ないのですか?
常にsum(1 for i in iterable)
同等のものとして使用できますがlen()
、そもそも反復可能を使用しないのはなぜですか?
多くの反復可能オブジェクトは、明確に定義されたlenを持たないジェネレータ式によって定義されます。永遠に繰り返される次のものを取りなさい:
def sequence(i=0):
while True:
i+=1
yield i
基本的に、長さを明確に定義するには、オブジェクト全体を前もって知る必要があります。それをのような関数と比較してsum
ください。オブジェクト全体を一度に知って合計する必要はありません。一度に1つの要素を取得して、すでに合計したものに追加するだけです。
のようなイディオムには注意してくださいsum(1 for i in iterable)
。多くの場合、反復可能であるため、使用できなくなります。または、多くの計算が含まれる場合、i番目の要素を取得するのに時間がかかる可能性があります。なぜアプリオリの長さを知る必要があるのかを自問する価値があるかもしれません。これにより、使用するデータ構造のタイプについての洞察が得られる場合があります(多くの場合list
、tuple
正常に機能します)。または、を呼び出すことなく操作を実行できる場合がありますlen
。
これは反復可能です:
def forever():
while True:
yield 1
しかし、長さはありません。有限のイテラブルの長さを知りたい場合、イテラブルとは何か(最後に到達するまで次の要素を取得するために繰り返し呼び出すことができるもの)の定義により、イテラブルを完全に拡張することが唯一の方法です。 、例:
len(list(the_iterable))
mgilsonが指摘したように、あなたは自分自身に問いかけたいかもしれません-なぜあなたは特定の反復可能なものの長さを知りたいのですか?コメントしてください。具体的な例を追加します。
処理する代わりに、処理した要素の数を追跡する場合は、次のようにします。
num_elements = len(the_iterable)
for element in the_iterable:
...
行う:
num_elements = 0
for element in the_iterable:
num_elements += 1
...
理解に含まれる要素の数を確認するためのメモリ効率の高い方法が必要な場合は、次のようになります。
num_relevant = len(x for x in xrange(100000) if x%14==0)
これを行うのは効率的ではありません(リスト全体は必要ありません):
num_relevant = len([x for x in xrange(100000) if x%14==0])
sum
おそらく最も便利な方法ですが、それは非常に奇妙に見え、あなたが何をしているのかすぐにはわかりません:
num_relevant = sum(1 for _ in (x for x in xrange(100000) if x%14==0))
したがって、おそらく独自の関数を作成する必要があります。
def exhaustive_len(iterable):
length = 0
for _ in iterable: length += 1
return length
exhaustive_len(x for x in xrange(100000) if x%14==0)
長い名前は、反復可能オブジェクトを消費することを思い出させるためのものです。たとえば、これはあなたが思うようには機能しません。
def yield_numbers():
yield 1; yield 2; yield 3; yield 5; yield 7
the_nums = yield_numbers()
total_nums = exhaustive_len(the_nums)
for num in the_nums:
print num
exhaustive_len
すでにすべての要素を消費しているからです。
編集:ああ、その場合exhaustive_len(open("file.txt"))
は、ファイル内のすべての行を1つずつ処理していくつあるかを確認する必要があるため、を使用します。を呼び出してファイル全体をメモリに保存するのは無駄list
です。