Python学習4:ジェネレータ、lamda式およびmap、reduce、filter関数

4335 ワード

map、reduce、filter関数を説明する前に、反復オブジェクト(iterable object)とジェネレータに関する概念について説明します.
1.反復オブジェクト(iterable object)
反復オブジェクトは、python 3 xでnext()メソッド(_next_()メソッド)を含むオブジェクトであり、このメソッドの目的は次の結果に進み、一連の結果が終了した後、StopIterationエラーを投げ出すことである.
ループ構造(forなど)がループオブジェクトを呼び出すと、ループのたびにnext()メソッドが呼び出され、StopIterationが現れるまで、forループが受信すると、ループが終了したことがわかり、next()の呼び出しが停止します.
私たちがtestを持っているとします.txtファイルには、次の内容が含まれています.
123
abc
456

呼び出すと:
>>>f.open('test.txt')
>>>f.next()
>>>f.next()
..
最後にStopIterationが現れるまでf.next()を入力し続けます
Open()は、next()メソッドを含む実際のループオブジェクトを返します.このnext()メソッドは,毎回新しい行の内容を返し,ファイルの最後に達するとStopIterationを挙げる.これで、私たちは手作業で循環することに相当します.
自動で行うと、次のようになります.
for line in open('test.txt'):
    print line

ここで、for構造はnext()メソッドを自動的に呼び出し、そのメソッドの戻り値をlineに与える.ループはStopIterationが出た時点で終了することを知っている.
シーケンスに対して反復オブジェクトでループを制御する利点は、ループが開始されたばかりのときにすべての要素を生成しなくてもよいことです.使用する要素は、ループ中に逐次生成されます.これにより、スペースが節約され、効率が向上し、プログラミングの柔軟性が向上します.
iter()関数と反復器(iterator)
技術的には、反復オブジェクトとforループ呼び出しの間には、反復オブジェクトを反復器(iterator)に変換する中間層がある.この変換はiter()関数を用いて実現した.しかし、論理的には、このレイヤを無視することが多いため、反復オブジェクトと反復器は互いに相手を指すことが多い.
2.ジェネレータ(Generator)
ジェネレータの主な目的は、ユーザーがカスタマイズしたループオブジェクトを構成することです.
ジェネレータの作成方法は関数定義と似ていますが、returnの場所でyieldに変更されます.ジェネレータには複数のyieldがあります.ジェネレータがyieldに遭遇すると、ジェネレータの実行が一時停止し、yieldの後の値が返されます.ジェネレータを再び呼び出すと、さっき一時停止した場所から次のyieldまで動作し続けます.ジェネレータ自体は反復するたびにyieldが返す値を使用する反復器を構成します.
def gen():
    a = 100
    yield a
    a = a*8
    yield a
    yield 1000

このジェネレータには3つのyieldがあり、ループとして使用すると3回のループが行われます.
for i in gen():
    print i

次のジェネレータを考慮します.
def gen():
    for i in range(4):
        yield i

3.ジェネレータ式
シーケンスが長すぎて、要素を1つずつ取得する必要がある場合は、リスト解析ではなくジェネレータ式を使用することを考慮する必要があります.リスト解析ではリストが返され、ジェネレータ式ではジェネレータが返されるため、メモリが節約され、効率が向上します.
ジェネレータ式の構文はリスト解析と同様ですが、ジェネレータ式は[]ではなく()で囲まれています.
上記ジェネレータは、
ジェネレータ式(Generator Expression)
:
G = (x for x in range(4))

4. filter()
filter(bool_func,seq):この関数の機能はフィルタに相当し、ブール関数bool_を呼び出します.funcは、各seq内の要素を反復的に巡回する.bool_を返すseqは、trueの値を持つ要素のシーケンスを返します.
例:
>>> filter(lambda x : x%2 == 0,[1,2,3,4,5])  
[2, 4]  

5. map()
map(func,seq):seqの要素を順次func(item)を実行し、結果をlistとして返す.funcがNoneの場合、funcはアイデンティティ関数として表現され、各シーケンスの要素セットを含むn個のメタグループのリストを返します.
>>> map(lambda x : None,[1,2,3,4])  
[None, None, None, None]  
>>> map(lambda x : x * 2,[1,2,3,4])  
[2, 4, 6, 8]  
>>> map(lambda x : x * 2,[1,2,3,4,[5,6,7]])  
[2, 4, 6, 8, [5, 6, 7, 5, 6, 7]]  
>>> map(lambda x : None,[1,2,3,4])  
[None, None, None, None] 

またmapは複数のsequenceをサポートしており、functionも対応する数のパラメータ入力をサポートする必要があります.
>>> def add(x, y): return x+y 
>>> map(add, range(8), range(8)) 
[0, 2, 4, 6, 8, 10, 12, 14]

6. reduce()
reduce(func,seq[,init]):funcは二元関数であり、funcをseqシーケンスの要素に作用させ、毎回一対(前の結果および次のシーケンスの要素)を携帯し、既存の結果と次の値を連続的に演算し、その後、得られた結果を後のシーケンス要素に作用させ、最終的に単一の値を返す.初期値initが与えられると、最初の比較は、シーケンスの最初の2つの要素ではなくinitと最初のシーケンス要素になります.
>>> reduce(lambda x,y : x + y,[1,2,3,4])  
10  
>>> reduce(lambda x,y : x + y,[1,2,3,4],10)  
20  
>>> def add(x,y): return x + y 
>>> reduce(add, range(1, 11)) 
55 ( :1+2+3+4+5+6+7+8+9+10)
>>> reduce(add, range(1, 11), 20) 
75 ( :1+2+3+4+5+6+7+8+9+10+20)

lambda:
これはPythonが面白い文法をサポートしています.これにより、C言語のマクロのような単行の最小関数を迅速に定義できます.lambdaという関数は、LISPから借りたもので、関数が必要な場所で使用できます.
>>> g = lambda x: x * 2 
>>> g(3) 
6 
>>> (lambda x: x * 2)(3) 
6

7.関数をパラメータとして渡す
関数は、オブジェクトとしてパラメータを渡すことができます.関数名(funcなど)は、カッコを必要としないオブジェクトを指します.たとえば、
def test(f, a, b):
    print 'test'
    print f(a, b)

test(func, 3, 5)

test関数の最初のパラメータfが関数オブジェクトであることがわかります.funcをfに渡すとtestのf()は実際にfunc()が実現する機能である.
これにより、プログラムの柔軟性が大幅に向上します.funcの代わりに別の関数があると仮定すると、同じtest関数を使用することができます.次のようになります.
test((lambda x,y: x**2 + y), 6, 9)