私は次のコードを持っています:
[x ** 2 for x in range(10)]
Python Shellで実行すると、次のように返されます。
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
私は検索しましたが、これはlist comprehensionと呼ばれているようですが、どのように機能しますか?
リスト内包表記は、リストを作成する簡潔な方法を提供します。一般的なアプリケーションは、各要素が別のシーケンスまたは反復可能オブジェクトの各メンバーに適用されたいくつかの操作の結果である新しいリストを作成するか、特定の条件を満たすそれらの要素のサブシーケンスを作成することです。
あなたの質問について、リスト内包表記は次の「プレーン」と同じことを行いますPythonコード:
>>> l = []
>>> for x in range(10):
... l.append(x**2)
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
どのように1行で記述しますか?うーん...できる...... map()
を lambda
とともに使用:
>>> list(map(lambda x: x**2, range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
しかし、リスト内包表記を使用する方が明確で簡単ではありませんか?
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
基本的に、x
で何でもできます。 x**2
だけではありません。たとえば、x
のメソッドを実行します。
>>> [x.strip() for x in ('foo\n', 'bar\n', 'baz\n')]
['foo', 'bar', 'baz']
または、x
を別の関数の引数として使用します。
>>> [int(x) for x in ('1', '2', '3')]
[1, 2, 3]
たとえば、x
をdict
オブジェクトのキーとして使用することもできます。どれどれ:
>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [d[x] for x in ['foo', 'baz']]
['10', '30']
組み合わせはどうですか?
>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [int(d[x].rstrip('0')) for x in ['foo', 'baz']]
[1, 3]
等々。
リスト内包でif
またはif...else
を使用することもできます。たとえば、range(10)
には奇数のみが必要です。できるよ:
>>> l = []
>>> for x in range(10):
... if x%2:
... l.append(x)
>>> l
[1, 3, 5, 7, 9]
ああ、複雑すぎます。次のバージョンはどうですか?
>>> [x for x in range(10) if x%2]
[1, 3, 5, 7, 9]
if...else
三項式を使用するには、x
の後にif ... else ...
を、range(10)
の後にnotを置く必要があります。
>>> [i if i%2 != 0 else None for i in range(10)]
[None, 1, None, 3, None, 5, None, 7, None, 9]
nested list comprehension について聞いたことがありますか?2つ以上のfor
sを1つのリスト内包に含めることができます。例えば:
>>> [i for x in [[1, 2, 3], [4, 5, 6]] for i in x]
[1, 2, 3, 4, 5, 6]
>>> [j for x in [[[1, 2], [3]], [[4, 5], [6]]] for i in x for j in i]
[1, 2, 3, 4, 5, 6]
最初の部分、for x in [[1, 2, 3], [4, 5, 6]]
と[1, 2, 3]
を与える[4, 5, 6]
について話しましょう。次に、for i in x
は、1
、2
、3
および4
、5
、6
を提供します。
警告:for x in [[1, 2, 3], [4, 5, 6]]
beforefor i in x
を常に置く必要があります:
>>> [j for j in x for x in [[1, 2, 3], [4, 5, 6]]]
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'x' is not defined
内包表記の設定、dict内包表記、およびジェネレータ式もあります。
set comprehensionsとリスト内包表記は基本的に同じですが、前者はリストの代わりにセットを返します。
>>> {x for x in [1, 1, 2, 3, 3, 1]}
{1, 2, 3}
それは同じです:
>>> set([i for i in [1, 1, 2, 3, 3, 1]])
{1, 2, 3}
dict comprehensionはセット内包のように見えますが、{key: value for key, value in ...}
ではなく{i: i for i in ...}
または{i for i in ...}
を使用しています。
例えば:
>>> {i: i**2 for i in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
そしてそれは等しい:
>>> d = {}
>>> for i in range(5):
... d[i] = i**2
>>> d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
(i for i in range(5))
はタプルを提供しますか?いいえ、それは generator expression です。これはgeneratorを返します:
>>> (i for i in range(5))
<generator object <genexpr> at 0x7f52703fbca8>
それは同じです:
>>> def gen():
... for i in range(5):
... yield i
>>> gen()
<generator object gen at 0x7f5270380db0>
そして、あなたはそれをジェネレータとして使うことができます:
>>> gen = (i for i in range(5))
>>> next(gen)
0
>>> next(gen)
1
>>> list(gen)
[2, 3, 4]
>>> next(gen)
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
注:関数内でリスト内包表記を使用している場合、その関数がジェネレーターをループできる場合は[]
は必要ありません。たとえば、 sum()
:
>>> sum(i**2 for i in range(5))
30
Related(ジェネレータについて): Pythonでのジェネレータについて 。
リスト、辞書、およびセットの内包はありますが、タプルの内包はありません(ただし、「ジェネレーター式」を調べてください)。
これらは、Pythonの従来のループがステートメント(何も返さない))であり、値を返す式ではないという問題に対処します。
これらはすべての問題の解決策ではなく、従来のループとして書き直すことができます。反復間で状態を維持および更新する必要がある場合、これらは扱いにくくなります。
それらは通常、次のもので構成されます。
_[<output expr> <loop expr <input expr>> <optional predicate expr>]
_
しかし、多くの興味深い奇妙な方法でねじれる可能性があります。
これらは、従来のmap()
およびfilter()
操作に類似しており、Python)に引き続き存在し、引き続き使用されます。
うまくできていれば、満足度の高い商売になります。
リスト内包表記がどのように機能するかについて、最近(他のSOの質問や同僚から)多くの混乱を見てきました。ほんの少しの数学教育は、なぜ構文がこのようなものであり、リスト内包表記が実際に意味することを助けることができます。
リスト内包表記は、数学でセットビルダー表記を使用する場合と同様に、セット/コレクションに対する述語と考えるのが最適です。私は数学の学位を持っているので、この表記は実際にはかなり自然な感じがします。しかし、私を忘れてください。Guidovan Rossum(Pythonの発明者)は数学の修士号を持ち、数学のバックグラウンドを持っています。
セットビルダー表記法の仕組みの(非常に基本的な)は次のとおりです。
したがって、このセットビルダー表記法は、厳密に正の数のセットを表します(つまり、[1,2,3,4,...]
)。
1)セットビルダー表記の述語フィルターは、保持するアイテムのみを指定し、リスト内包述語も同じことを行います。項目を省略するための特別なロジックを含めるには、述語に含まれていない限り省略されます。空の述語(つまり、最後に条件なし)には、指定されたコレクションのすべてのアイテムが含まれます。
2)セットビルダー表記の述語フィルターは最後に続き、リスト内包表記も同様です。(一部)初心者は[x < 5 for x in range(10)]
のようなものを考えます実際に[0,1,2,3,4]
を出力するときに、リストに[True, True, True, True, True, False, False, False, False, False]
を提供します。 Pythonに[True, True, True, True, True, False, False, False, False, False]
の all range(10)
の項目の評価を依頼したため、出力x < 5
が得られます。述語は、セットからすべてを取得することを意味しません(セットビルダー表記と同様)。
リスト内包表記を使用しているときにビルダーの表記法を覚えておくと、飲み込むのが少し簡単になります。
HTH!
何が起こっているのかをより視覚的に把握したい場合は、これが役立つでしょう:
# for the example in the question...
y = []
for x in range(10):
y += [x**2]
# is equivalent to...
y = [x**2 for x in range(10)]
# for a slightly more complex example, it is useful
# to visualize where the various x's end up...
a = [1,2,3,4]
b = [3,4,5,6]
c = []
for x in a:
if x in b:
c += [x]
# \ \ /
# \ _____\______/
# \ / \
# \/ \
# /\ \
# / \ \
# / \ \
c = [x for x in a if x in b]
print(c)
...出力を生成します[3, 4]
はじめに
リスト内包表記は、Pythonでリストを作成するための高レベルの宣言的な方法です。理解力の主な利点は、読みやすさと保守性です。多くの人々はそれらを非常に読みやすいと感じており、以前にそれらを見たことがない開発者でさえ、通常はそれが何を意味するかを正しく推測できます。
_# Snippet 1
squares = [n ** 2 for n in range(5)]
# Snippet 2
squares = []
for n in range(5):
squares.append(n ** 2)
_
両方のコードスニペットは、squares
を生成して_[0, 1, 4, 9, 16]
_と等しくなります。
最初のスニペットでは、入力するものがどのようなリストの種類を宣言しているのか、2番目は作成方法を指定していることに注意してください。これが、理解が高レベルで宣言的な理由です。
構文
_[EXPRESSION for VARIABLE in SEQUENCE]
_
EXPRESSION
は任意のPython式ですが、通常はいくつかの変数を持っています。この変数はVARIABLE
フィールドに記述されています。SEQUENCE
変数が列挙する値のソースを定義します。
スニペット1を考えると、[n ** 2 for n in range(5)]
:
EXPRESSION
は_n ** 2
_ですVARIABLE
はn
ですSEQUENCE
はrange(5)
ですsquares
のタイプを確認すると、リスト内包表記が単なる通常のリストであることがわかります。
_>>> type(squares)
<class 'list'>
_
式の詳細
式は、値に還元されるものであれば何でもかまいません。
n ** 2 + 3 * n + 1
_などの算術式n
を変数として使用するf(n)
のような関数呼び出しs[::-1]
_のようなスライス操作bar.foo()
いくつかの例:
_>>> [2 * x + 3 for x in range(5)]
[3, 5, 7, 9, 11]
>>> [abs(num) for num in range(-5, 5)]
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal.upper() for animal in animals]
['DOG', 'CAT', 'LION', 'TIGER']
_
フィルタリング:
最終リストの要素の順序は、SEQUENCE
の順序によって決まります。ただし、if
句を追加して要素を除外できます。
_[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]
_
CONDITION
は、True
またはFalse
に評価される式です。技術的には、条件はVARIABLE
に依存する必要はありませんが、通常はそれを使用します。
例:
_>>> [n ** 2 for n in range(5) if n % 2 == 0]
[0, 4, 16]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal for animal in animals if len(animal) == 3]
['dog', 'cat']
_
また、Pythonを使用すると、リスト以外の種類の理解を記述できるようになります。