←PC版は別ページ

≪いっしょにPython≫
プログラマーの実験ノート

 このページは,プログラム言語Pythonをこれから学ぼうと考えている筆者の備忘録です.
 そこそこ調べて書いていますが,仕様を精密に調べたものではありません.どちらかと言えば,実装されたPython 3を使ってみてどうなったかということを中心に書いたものです.いわば,実験ノートの記録です.(最終更新年月日:2019.4.20 / by Python 3.7.3)
Pythonの練習には,
(1) IDLEというメニューから入って,>>>というプロンプトが表示される状態で使う場合
• 画面の上端がPython 3.7.x Shellとなっていて,2行目がFile, Edit, Shell, Debug, ...となっている
• 1行入力するたびに,エラーを確かめながら処理を進める,対話型インタプリタの形になっている
(2) IDLEというメニューから入って,左上端のFileをクリック→New Fileと進む場合
• 画面の上端がファイル名(初めはUntitled)となっていて,2行目がFile, Edit, format, Run, ...となっている
(3) Python 3.7.x という真っ黒なコマンドプロンプトの画面(ターミナルウィンドウ)から入るもの
の3通りが使えるが,以下は(2)のNew Fileから,テキストエディタを使って,プログラムを書く場合を考える.

1. lambda式(lambda構文,lambda文,ラムダ関数,無名関数)

〜用語にはバリエーションあり〜
ラムダ式 … Python 3.7.3 ドキュメント
… 「Pythonの教科書」(クジラ飛行机著:マイナビ出版 p.131)
… 「Pythonプログラミング」(金城俊哉著:秀和システム p.165)
ラムダ関数 … 「入門Python3」(Bill Lubanovic著,斎藤康毅監訳,...:O'REILLYジャパン p.123)
lambda式 … 「Python文法詳解」(石本敦夫著:O'REILLYジャパン p.196)
lambda構文 … 「Python入門」(株式会社エスキュービズム著:秀和システム p.222)
… 「Fluent Python」(Luciano Romalho著,豊沢聡,桑井博之監訳,梶原玲子訳:O'REILLYジャパン p.154)
⇒ この教材では,主に「lambda式」と呼ぶことにする.なお,初歩的なことであるが,ギリシャ文字のラムダを英語表記にするとlambdaになり,無音字のbを書かなければならない.これを忘れるとエラーになる.…他に無音字のbが付く英単語には,climb(登る),bomb(爆弾),coulomb(クーロン:フランスの物理学者)などがある.

(1)lambda式を使ってみる
【書式】
lambda 引数1, 引数2, ... : 式
• 引数は複数個指定できる.可変長引数 *arg,キーワード引数なども使える
• 通常の関数とは異なり,return文は書かない.: の後の式が関数の戻り値として返される.
• この関数には,複数行にわたるif文やfor文は使えない.1行に収まる式のみ可能.
【例 2.8.1】
IDLE → New File → Save as .. → Run
f1 = lambda x, y:x * y
z1 = f1(3, 4)
print(z1)
12
• この形でlambda式を使う場合は,次の形で関数f1()を定義した場合と同じ結果になる.
• この場合,変数f1に代入しているように見えるが,print(globals())によってglobalな変数,関数を表示してみると分かるように,代入したものがlambda式という関数だから,f1は関数として登場する.
• この関数に引数を代入するには,通常の関数と同様にf1(3,4)などと書く.
def f1(x, y):
    return x * y
z1 = f1(3, 4)
print(z1)

(2) lambda式に引数を渡すには…その1
• 上記の2.8.1のように関数に,「まず名前を付けて」「次にその関数に引数を渡す」という手順を踏めば,lambda式に引数を渡すことができますが,そのようにすると,lambda式が別名「無名関数」と呼ばれている良さを生かしているとは言えない.
• lambda式の内部は,一般の関数と同様にlocalな空間になるので,
lambda 仮引数1, 仮引数2 : 式
の仮引数1,2は,その外側に同名の変数があっても,その値とは全く関係ない.次の例2.8.2では,予想に反して(3*3→)9などとはならない.

【例 2.8.2】
IDLE → New File → Save as .. → Run
x1 = 3
y = lambda x1: x1*x1
print(y)
<function <lambda> at 0x03169348>
• 次のように,lambda式に括弧を付けて,引数も括弧に入れて渡すと,一応目指す結果は得られるが,このような回りくどいことをするくらいなら,普通に関数を定義して,引数を渡せば十分だという印象を受ける.
【例 2.8.3】
IDLE → New File → Save as .. → Run
y = (lambda x1: x1*x1)(3)
print(y)
9

(3) lambda式に引数を渡すには…その2
• 変数や関数に名前を付けるのは,何度も使えるようにするためであることが多い.これに対して,lambda式は「無名関数」とも呼ばれ,「その場で」「1回だけ」「使い切りで」使うのに適している.
• 実際上は,他の関数の引数として関数を渡したいときに,その引数に使う関数を書くのに適している.

≪利用例1:ソート(並び替え)での利用≫
• L1がリスト,タプル,文字列などのイテラブル(ここでは,要素を1つずつ取り出す反復処理ができるオブジェクトと解釈する)であるとき
組み込み関数(ビルドイン関数)sorted()を利用するには
【書式】
L2 = sorted(L1)
… 元のL1を並び替えたL2ができる.元のL1は変化しない.
L2 = sorted(L1, key=None, reverse=False) key,reverseはオプション
… keyには関数を指定し,L1の各要素から比較キーを展開するのに使う.デフォルト値はNoneで,要素が直接比較される.
… オプションの引数,keyとreverseはキーワード引数として指定する.reverse=Trueとすると逆順になる.
• 元のデータL1がリストであるとき,
【書式】
L1.sort()
によって,上と同様の結果が得られるが,この方法では元のデータが書き換わる所が上記と異なる.
【例 2.8.4】
IDLE → New File → Save as .. → Run
L1 = [3,1,5] #リスト
L2 = sorted(L1)
print(L2)
[1, 3, 5]
なお,L1は変化せずに元のまま残っている.

【例 2.8.5】
IDLE → New File → Save as .. → Run
LL1 = [[2,1],[5,4],[6,3]] ##リストのリスト(二重リスト)
LL2 = sorted(LL1, key=lambda s:s[0])
print(LL2)
[[2, 0], [5, 3], [6, 1]]
sorted()の第1引数にイテラブルLL1を渡したとき,key関数はその各要素LL1[k]に対して呼び出される関数を指定する.この例では,二重リストの1つの要素[2, 0]などをsとしたとき,その第0要素の2を返すから,第0要素でソートしたものができる.

【例 2.8.6】
IDLE → New File → Save as .. → Run
tup1 = (('Sun','A',11),('Mon','C',10),
('Tue','B',12),('Wed','A',9))##タプルのタプル
tup2 = sorted(tup1, key=lambda s:s[2], reverse=True)
print(tup2)
[('Tue', 'B', 12), ('Sun', 'A', 11), ('Mon', 'C', 10), ('Wed', 'A', 9)]
sorted()の第1引数にイテラブルtup1を渡したとき,key関数はその各要素tup1[k]に対して呼び出される関数を指定する.この例では,二重タプルの1つの要素('Sun','A',11)などをsとしたとき,その第2要素の11を返すから,第2要素でソートしたものができる.ただし,reverse=Trueだから,逆順ソートになる.
 なお,元のイテラブルがタプルのタプルであっても,sorted()によって返されるものは,タプルのリストになる.

【例 2.8.7】
IDLE → New File → Save as .. → Run
TL1 = [('もり','みつこ'),('もり','まさこ'),
('もりの','くま'),('もりた','たもり')]
TL2 = sorted(TL1, key=lambda s:(s[0],s[1]))
print(TL2)
[('もり', 'まさこ'), ('もり', 'みつこ'), ('もりた', 'たもり'), ('もりの', 'くま')]
(姓,名)になっているタプルのリストを姓順→名順に多重ソートするには,lambda式の:の後の式を括弧でくくって,カンマで区切って並べる.

【例 2.8.8】
IDLE → New File → Save as .. → Run
TL1 = [('car','white',63),('car','blue',85),
('bike','red',10)]
TL1.sort(key=lambda s:(s[0],len(s[1])))
print(TL1)
[('bike', 'red', 10), ('car', 'blue', 85), ('car', 'white', 63)]
• 第0要素のアルファベット順に並べ,それらが同じものについては第1要素の文字の短い順に並べる.多重ソートするには,lambda式の:の後の式を括弧でくくって,カンマで区切って並べる.
• 元のリストが並び替わる.


≪利用例2:関数max(),min()での利用≫
• 関数max()は,イテラブルの最大値を返す.関数min()は最小値を返す.
【書式】
max(イテラブル)
• リストなどのイテラブルが整数や浮動小数点から成っているとき,関数max()にイテラブルだけを渡すと,その最大値が返される
min(イテラブル)
• リストなどのイテラブルが整数や浮動小数点から成っているとき,関数min()にイテラブルだけを渡すと,その最小値が返される
【例 2.8.9】
IDLE → New File → Save as .. → Run
L1 = [1, 2.1, -3, -1.3]
m1 = max(L1)
print(m1)
2.1
整数は浮動小数点数として比較される

【例 2.8.10】
IDLE → New File → Save as .. → Run
L1 = ['PQR','pq','a','AB']
m1 = max(L1)
print(m1)
pq
文字列のリストでは,文字列としてアルファベット(日本語なら50音順)に並べた時の最後の文字列になる.なお,アルファベット大文字は小文字よりも前で,1文字目が同じなら2文字目で比較される.

【例 2.8.11】
IDLE → New File → Save as .. → Run
TL1 = [(1, 6),(3, 0), (-2, 4)]
m1 = max(TL1)
print(m1)
(3, 0)
タプルのリスト,リストのリストのように1つの要素が複数のものからできている場合,イテラブルだけを指定してmax()を求めると,第0要素によって比較が行われる.

【書式】
max(イテラブル, key=比較関数)
• 比較関数を指定するには,key=と書く.min()関数についても同様
【例 2.8.12】
IDLE → New File → Save as .. → Run
TL1 = [(1, 6),(3, 0), (-2, 4)]
m1 = max(TL1, key=lambda t:t[1])
print(m1)
(1, 6)
リストの1つの要素(タプル)例えば(1,6)を仮引数tで表すとき,t[1]はその2つ目の要素を表すので,lambda式によりタプルの2つ目の要素をkeyとして比較することになる.2つ目の要素が最大となるのは
m1 = (1, 6)

【例 2.8.13】
IDLE → New File → Save as .. → Run
LL1 = [['a','arm'],['d','doctor'],['b','by'],
['c','cold']]
m1 = max(LL1, key=lambda t:len(t[1]))
print(m1)
['d', 'doctor']
リストの1つの要素(リスト)例えば['a','arm']を仮引数tで表すとき,t[1]はその2つ目の要素armを表し,len(t[1])はその長さ(文字数)を表すので,lambda式によりリストの2つ目の要素の長さをkeyとして比較することになる.2つ目の要素の長さが最大となるのは
m1 = ['d','doctor']

【例 2.8.14】
IDLE → New File → Save as .. → Run
L1 = ['0', 12, 2, '1']
m1 = max(L1, key=lambda t:str(t))
print(m1)
2
文字列と数値の大小は直接比較できない.str()関数を使うと,数値も文字列と見なして比較することができる.ただし,文字列としては,'12'<'2'となる点に注意
また,比較関数としてstr()を使ったとしても,元の要素は結果として変化しない.

【例 2.8.15】
IDLE → New File → Save as .. → Run
L1 = ['0', 12, 2, '1']
m1 = max(L1, key=lambda t:int(t))
print(m1)
12
文字列と数値の大小は直接比較できないが,int()関数を使うと,整数と見なせる文字列は整数と見なして比較することができる.この場合は2<12となる

≪利用例3:関数map()での利用≫
【書式】
map(関数, イテラブル)
• 関数map()は,イテラブルのすべての要素に関数を適用した結果を返す.結果は,mapオブジェクトになり,そのままでは表示できないが,リスト型に変換すれば表示できる.
map(関数, イテラブル1, イテラブル2)
• イテラブル1,イテラブル2のように複数のイテラブルが与えられたときは,要素数の少ない方まで関数が適用される.
【例 2.8.16】 イテラブルの要素を1文字で表し,仮引数にする
IDLE → New File → Save as .. → Run
L1 = [2, -1, 3]
m1 = map(lambda t: t*t, L1)
L2 = list(m1)
print(L2)
[4, 1, 9]
リストL1の1つの要素,例えば2を仮引数tで表すとき,t*tはその2乗を表すので,lambda式により各要素の2乗から成るmapオブジェクトができる.
リスト型に変換すれば,表示できる.

【例 2.8.17】 複数のイテラブルの要素を使った演算
IDLE → New File → Save as .. → Run
L1 = [1, -2, 3]
L2 = [0, 3, -1, 4]
m1 = map(lambda s,t: s*s*t, L1, L2)
L3 = list(m1)
print(L3)
[0, 12, -9]
リストL1の1つの要素をs,L2の1つの要素をtとしたとき,lambda式によりsの2乗×tから成るmapオブジェクトができる.
ただし,L1の要素数は3で,L2の要素数は4だから,少ない方に合わせて,3個まで計算が行われる.

【例 2.8.18】 lambda式の戻り値を2つにする
IDLE → New File → Save as .. → Run
TL1 = [\
        [[1,2], [2,0]],\
       [[3,1], [1,4]],\
       [[-1,0], [2,-1]]\
        ]
m1 = map(lambda t:( sum(t[0]),sum(t[1]) ), TL1)
T2 = list(m1)
print(T2)
[(3, 2), (4, 5), (-1, 1)]
• リストのリストTL1をイテラブルとすると,その1つの要素tとは,上記の\で囲まれた二重ブラケット[[ ]]の部分,例えば[[1,2], [2,0]]になる.
• ここで,一番内側のリスト,例えば[1,2]はt[0],[2,0]はt[1]だから,[1,2]や[2,0]の各々の和を求めたいとすると,sum(t[0])とsum(t[1])になる.
• lambda式の戻り値を2つにするには,:の後を括弧でくくって,値を2つ並べるとよいから,( sum(t[0]),sum(t[1]) )とする.
【例 2.8.19】 lambda式にif文を使う
• 辞書型のデータd1があるとき,d1.keys()によりキー一覧のリストができ,d1.values()により値一覧のリスト,d1.items()により(キー,値)のタプル一覧のリストができる.
• if文を1行で書くには,条件成立の場合の値 if 条件 else 条件不成立の場合の値 とする.
IDLE → New File → Save as .. → Run
d1 = {3:'osaka', 2:'kobe',4:'kyoto'}
m1 = map(lambda t: t[1] if t[0] > 2 else '', 
d1.items())
L1 = list(m1)
print(L1)
['osaka', '', 'kyoto']
• キーが2よりも大きい都市名をリストにするという設定で考える.
• d1が辞書型だから,d1.items()でキー,値のタプル一覧のリストができる.その1つの要素をtで表すと,t[0]はキー,t[1]は値になる.そこで,キーが2よりも大きいという条件は、t[0]>2となる.

【書式】
filter(関数, イテラブル)
• リストやタプルなどのイテラブルから要素を1つずつ取り出し,関数の戻り値がTrueとなるものだけでfilter型オブジェクトを作る.これをlist()によりリスト型にすれば表示できる.
• 元のイテラブルは変化しない.
【例 2.8.20】
IDLE → New File → Save as .. → Run
L1 = [1, -2, 3, -4, 5]
m1 = filter(lambda t: t>2, L1)
L2 = list(m1)
print(L1, L2)
[1, -2, 3, -4, 5] [3, 5]
• リストL1の1つの要素をtとおくと,lambda式はt>2であるときTrueを返し,t<=2のときFalseを返すから,t>2となる要素だけから成るリストができる.
• 元のリストL1はそのまま残っている.

【例 2.8.21】
IDLE → New File → Save as .. → Run
d1 = {3:'osaka', 2:'kobe',4:'kyoto'}
m1 = filter(lambda t: t[0] > 2 , d1.items())
L1 = list(m1)
print(L1)
[(3, 'osaka'), (4, 'kyoto')]
• d1.items()により,辞書型d1をリストに変えて,キー,値のタプル一覧になる.その1つの要素、例えば(3, 'osaka')の初めの要素が2よりも大きなものだけを選んで,リストを作る.
• filter()関数を使えば,関数の戻り値がTrueとなるものだけを要素に選んで新たなオブジェクトを作るから,if文は不要になる.

【例 2.8.22】
IDLE → New File → Save as .. → Run
LL1 = [[2, 1],[3, 7],[1, 4]]
F1 = filter(lambda t:sum(t) % 3 , LL1)
L1 = list(F1)
print(L1)
[[3, 7], [1, 4]]
• LL1がリストのリストであるとき,LL1の1つの要素tは[2,1]のようなリストになる.
• sum(リスト)関数は,リストのすべての要素の和を返す.
• %3は3で割った余り0,1,2を返すが,真偽値True,Falseとの対応は,0が偽,それ以外はすべて真となるから,3で割り切れるとき偽,3で割って1または2余るとき真となる.10%3→1, 5%3→2は真となるから,後ろ2つの要素が選ばれ,先頭の要素は捨てられる.

【例 2.8.23】
IDLE → New File → Save as .. → Run
L1 = ['abc','bcd','cda']
F1 = filter(lambda t: 'bc' in t , L1)
L1 = list(F1)
print(L1)
['abc', 'bcd']
• L1が文字列のリストであるとき,L1の1つの要素tは'abc'のような文字列になる.
• in演算子は,検索要素 in リスト の形で使うと,リストの中に指定した要素が含まれていればTrueを返し,そうでなければFalseを返す.
• 文字列の内で,'bc'が部分一致するのは,初めの2つの要素.

○== メニューに戻る ==