tuneoの日記: メモ;イテレータを使った愉快な諸々について(その1)
さらに続き。イテレータとジェネレータを使って色々愉快なことができるんだぜ、というのをメモる。今日は組み込み関数編。
all(iterable)は、iterableの全要素がTrueだった場合にTrueを返す。以下の例では文字列が全てアルファベット小文字かどうかを検査している(実用上はstr.islower()を使う)。
>>> m = (c.islower() for c in "Hello")
>>> all(m)
False
>>> n = (c.islower() for c in "world")
>>> all(m)
True
any(iterable)はiterableの要素が一つでもTrueなら、Trueを返す。
>>> m = (c.islower() for c in "Hello")
>>> any(m)
True
>>> n = (c.islower() for c in "HELLO")
>>> any(n)
False
enumerate(iterable[, start = 0])は「インデックス値とiterableの各要素の組(タプル)を生成するイテレータ」を返す。インデックス値の初期値はデフォルトでは0だが、二つ目の引数startで指定することもできる。
>>> i = iter("hello")
>>> e = enumerate(i)
>>> e.next()
(0, 'h')
>>> e.next()
(1, 'e')
filter(func, iterable)は、iterableの各要素を引数として関数funcを呼び出し、返値がTrueの要素だけから成るリストを返す。以下の例では0から9までの整数のうち、偶数だけを抽出したリストを得ている。昔はともかく、リスト内包表記が使える今となってはあまり使わない。
>>> ir = iter(xrange(10))
>>> filter(lambda x: (x % 2) == 0, ir)
[0, 2, 4, 6, 8]
>>> [x for x in xrange(10) if (x % 2) == 0]
[0, 2, 4, 6, 8]
iter(o[, sentinel])はオブジェクトからイテレータオブジェクトを作る。oに「イテレータを生成可能なオブジェクト(文字列・リスト・タプル・その他のシーケンス)」だけを渡す(sentinelは指定しない)と、その中身を総ざらえにしてくれるイテレータを作ってくれる、というのが一つ目のポピュラーな使い方。
oに関数オブジェクト、sentinelに任意の値を渡してもイテレータを作ってくれるが、このイテレータはnext()を呼び出すと関数oを呼び出し、その値がsentinelと等しければStopIteration例外を発生させ、そうでなければその値を返す。これが二つ目のマイナーな使い方になる。
一つ目の使い方はありきたりなので、以下にiter()のもう一つの使い方についてのサンプルを示す。ここではf.readline()を呼び、返値が""でないなら(EOFでないなら)その値(ファイルから読み込んだ1行)を返すイテレータを作り、forループで行を表示している。ファイルオブジェクトはそれ自身がイテレータなので、以下のコードは掛け値なしの車輪の再発明、全く無価値であることに注意。
f = file(filename, "r")
fileiterator = iter(f.readline, "")
for l in fileiterator:
print x
map(function, iterable)は、iterableの写像(iterableの各要素を引数として関数functionを呼び出した戻り値を要素とするリスト)を返す。以下の例では0から4の整数から成るリストを作成し、その各要素が偶数であるか無いかを判定した真偽値のリストを作っている。これもリスト内包表記で代替可能なので、今となってはあまり使われない。
>>> iseven = lambda x: (x % 2) == 0
>>> map(iseven, range(5))
[True, False, True, False, True]
>>> [iseven(x) for x in range(5)]
[True, False, True, False, True]
max()は最大値を求めるための関数なのだが、二通りの使い方が出来る。まず一つ目がmax(iterable[, key = function])という使い方。これはiterable(シーケンスだの文字列だの)の要素の中から最大値を求める、というもの。キーワード引数keyには、max()の内部で呼ばれているlist.sort()に渡される引数を指定する(ここではlist.sortの詳細については触れないが、後述のsortedの説明参照)。
>>> l = [0, -1, 5, 2, 15, 6]
>>> max(l)
15
もう一つはmax(arg1[, arg2, ...][, key = function])という使い方。これは可変引数の仕組みを使って、与えられた複数の引数の中の最大値/最小値を求める。keyに付いては前述の通り。
>>> max(0, -1, 5, 2, 15, 6)
15
min()は求めるのが最大値でなく最小値になる以外はmax()と全く同じなので省略。
next(iterator[, default])は……iterator.next()を呼んでその値を返すが、イテレータがすっからかんになったらdefaultを返すところがiterator.next()と違う。defaultが与えられていなければ、iterator.next()を直接呼ぶのと同様にStopIteration例外を発生させる。
reduce(function, iterable[, initializer])は、iterableの最初の二つの要素を引数にしてfunctionを呼び出し、その返値と三つめの要素を引数にしてfunctionを呼び出し……という具合に動作する。たとえば以下のコードは4の階乗を計算する。
>>> reduce(lambda x, y: x * y, range(1,5)) # (((1 * 2) * 3) * 4)
24
initializerを指定すると、iterableの最初の要素がinitializerであるかのように動作する。
>>> reduce(lambda x, y: x * y, range(1,5), -2) # ((((-2 * 1) * 2) * 3) * 4)
-48
特殊なケースにおける挙動は以下の通り。
- iterableの要素が一つしかなく、initializerが与えられている→function(initializer, iterableの唯一の要素)の値が返る。
- iterableの要素が一つしかなく、initializerが与えられていない→iterableの唯一の要素がそのまま返る。
- iterableが空で、initializerが与えられている→initializerの値がそのまま返る。
- iterableが空で、initializerも与えられていない→TypeError例外が発生する。
reversed(seq)は、シーケンスを逆に(末尾から先頭に向けて)辿るイテレータを返す。ちなみにseqは厳密に「シーケンス」でなければならず、イテレータは渡せない。
>>> for c in reversed("abcde"):
print c,
e d c b a
sorted(iterable[, cmp = None[, key = None[, reverse = False]]])は、iterableの要素を整列したリストを返す。省略可能な引数cmpは比較関数(デフォルトはNone→組み込み関数cmp()を使う)、keyは要素から比較関数に与える値を求める関数(デフォルトはNone→要素を直接比較する)、そしてreverseは逆順の整列を指示する(デフォルトではFalse→昇順の整列)フラグ。
>>> l = ["-10", "4", "0", "15"]
>>> sorted(l) # 文字列としてソート
['-10', '0', '15', '4']
>>> sorted(l, key = int) # 整数としてソート
['-10', '0', '4', '15']
>>> sorted(l, reverse = True, key = int) # 整数として逆順にソート
['15', '4', '0', '-10']
比較関数cmpはデフォルトではNoneで、その場合は組み込み関数cmpが使われる。x > yなら正の値、x == yなら0, x
>>> def mycmp(x, y): # やってることは組み込み関数cmp()と大差ない
if x > y:
return 1 # x > yなら正の値
elif x == y:
return 0 # xがyと等しいなら0
else: # x < y
return -1 # x < yなら負の値
>>> sorted(l, reverse = True, key = int, cmp = mycmp)
['15', '4', '0', '-10']
sum(iterable[, start = 0])はiterableの要素の合計し、start(デフォルトは0)を足した値を返す(当然、iterableの要素が全て「数」でないとエラーになる?)。
zip([iterable, ...]) は複数のiterableから一つずつ要素を取り出してタプルを作り、それを要素とするリストを返す。どれか一つのiterableがすっからかんになった時点で、それ以上タプルは作らない。zip()は引数を与えないと空のリストを返す。
>>> zip("abc", "defg")
[('a', 'd'), ('b', 'e'), ('c', 'f')] # 'g'は仲間はずれ
list(iterable)
tuple(iterable)
set(iterable)
frozenset(iterable)
与えられたiterableからリスト・タプル・集合・変更不能な集合を作る。
メモ;イテレータを使った愉快な諸々について(その1) More ログイン