web-dev-qa-db-ja.com

Pythonで[]なしのリスト内包表記

リストへの参加:

_>>> ''.join([ str(_) for _ in xrange(10) ])
'0123456789'
_

joinは反復可能にする必要があります。

明らかに、joinの引数は[ str(_) for _ in xrange(10) ]であり、それは リスト内包表記 です。

これを見てください:

_>>>''.join( str(_) for _ in xrange(10) )
'0123456789'
_

現在、joinの引数はstr(_) for _ in xrange(10)であり、_[]_はありませんが、結果は同じです。

どうして? str(_) for _ in xrange(10)もリストまたは反復可能を生成しますか?

71
Alcott
>>>''.join( str(_) for _ in xrange(10) )

これはgenerator expressionと呼ばれ、 PEP 289 で説明されています。

ジェネレータ式とリスト内包表記の主な違いは、前者はメモリ内にリストを作成しないことです。

式を記述する3番目の方法があることに注意してください。

''.join(map(str, xrange(10)))
57
NPE

他の回答者は、 generator expression (リストの内包表記に似た表記ですが、角括弧はありません)を発見したと答えました。

一般に、genexps(愛情を込めて知られているように)は、リスト内包表記よりもメモリ効率が高く、高速です。

ただし、''.join()の場合、リストの内包表記はより高速で、メモリ効率が高くなります。その理由は、joinがデータを2回通過する必要があるため、実際には実際のリストが必要だからです。それを与えると、すぐに作業を開始できます。代わりにgenexpを指定すると、genexpを使い果たしてメモリ内に新しいリストを作成するまで作業を開始できません。

~ $ python -m timeit '"".join(str(n) for n in xrange(1000))'
1000 loops, best of 3: 335 usec per loop
~ $ python -m timeit '"".join([str(n) for n in xrange(1000)])'
1000 loops, best of 3: 288 usec per loop

itertools.imapmapを比較しても同じ結果が得られます:

~ $ python -m timeit -s'from itertools import imap' '"".join(imap(str, xrange(1000)))'
1000 loops, best of 3: 220 usec per loop
~ $ python -m timeit '"".join(map(str, xrange(1000)))'
1000 loops, best of 3: 212 usec per loop
124

2番目の例では、リストの内包表記ではなく、ジェネレータ式を使用しています。違いは、リスト内包表記では、リストが完全に構築されて.join()に渡されることです。ジェネレータ式を使用すると、アイテムは1つずつ生成され、.join()によって消費されます。後者はより少ないメモリを使用し、一般的に高速です。

それが起こると、リストコンストラクターはジェネレーター式を含む反復可能なものを喜んで消費します。そう:

[str(n) for n in xrange(10)]

次のものの単なる「構文糖」です。

list(str(n) for n in xrange(10))

言い換えれば、リストの内包表記は、リストに変換される単なるジェネレータ式です。

5
kindall

前述のように、それは ジェネレータ式 です。

ドキュメントから:

引数が1つだけの呼び出しでは、括弧を省略できます。詳細については、セクション Calls を参照してください。

5
monkut

括弧ではなく括弧で囲まれている場合、技術的にジェネレータ式です。ジェネレーター式は、Python 2.4。

http://wiki.python.org/moin/Generators

結合後の部分、( str(_) for _ in xrange(10) )自体は、ジェネレータ式です。次のようなことができます:

mylist = (str(_) for _ in xrange(10))
''.join(mylist)

上記の2番目のケースで書いたものとまったく同じことを意味します。

ジェネレータにはいくつかの非常に興味深いプロパティがありますが、少なくとも、必要のないときにリスト全体を割り当てないということです。代わりに、joinのような関数は、ジェネレータ式からアイテムを1つずつ「ポンプ」し、小さな中間部分で作業を行います。

あなたの特定の例では、おそらくリストとジェネレーターの動作に大きな違いはありませんが、一般的に、可能な限りジェネレーター式(およびジェネレーター関数)を使用することを好みます。これは、ジェネレーターが完全なリスト実体化よりも遅い

4
sblom

それはリストの理解ではなくジェネレータです。ジェネレーターも反復可能ですが、リスト全体を最初に作成してから結合するのではなく、xrangeの各値を1つずつ渡します。これははるかに効率的です。

0
Daniel Roseman

2番目のjoin呼び出しの引数はジェネレーター式です。反復可能を生成します。

0