python4phper - phpユーザのためのpython入門 (python2.5)
DESCRIPTION
PHPユーザのためのPython入門です。PHPのコードとPythonのコードを並べて書いてるので、PHPユーザにとっては学習しやすいと思います。なお昔の資料なので、Pythonのバージョンが2.5であることに注意。TRANSCRIPT
日付
PHPユーザのためのPython入門Python4PHPer 第08回講習会 2010-10-03(Sun)
1
概要と特徴
2
概要✤ 動的なスクリプト言語✤ 世界中で人気(特にヨーロッパ)✤ 作者:Guido van Rossum(Google)✤ http://www.python.org/
3
長所✤ 簡潔な言語仕様と読みやすい構文✤ 強力な機能と豊富なライブラリ✤ 豊富なドキュメント(日本語訳あり)✤ 組織立った開発&明確なスケジュール✤ Windowsを公式にサポート
4
実績✤ YouTube(Webサイト全般)✤ Google(社内システム、Google AppEngine)✤ RedHat Linux (インストーラ, パッケージ管理システム)✤ Maya (ハイエンド3DCGソフト)✤ Blender (3Dモデリング・レンダリングソフト)✤ ERP5 (基幹業務パッケージ)✤ BitTorrent (P2P通信ソフト)✤ Skencil (ドローソフト)✤ Mercurial, Bazaar (バージョン管理システム)✤ 他多数
✤ http://www.python.org/about/success/✤ http://ja.wikipedia.org/Pythonを使っている製品あるいはソフトウェアの一覧
5
特徴(対PHP)✤ 見た目がきれい
✤ インデントを使った構文(見た目=意味)✤ 行末の「;」がいらない✤ 「$var」ではなく「var」✤ 「$this->method()」ではなく「self.method()」✤ 「array(10,20,30)」ではなく「[10, 20, 30]」✤ 「array('one'=>1)」ではなく「{'one':1}」
6
特徴(対PHP)✤ 本格的な言語仕様
✤ オブジェクト指向 (多重継承あり、インターフェースなし)✤ 関数オブジェクト、クロージャ✤ 例外機能 (finallyあり)✤ 名前空間(パッケージ、モジュール)✤ イテレータ、ジェネレータ
7
特徴(対PHP)✤ その他
✤ 汎用言語 (Webアプリに限定されない)✤ 配列と辞書とが別のデータ構造✤ インタラクティブシェルが標準機能✤ JavaScripと類似点が多い✤ 他の人からバカにされない✤ 国内では仕事がない
8
日本語ドキュメント✤ Python和訳ドキュメント
✤ http://www.python.jp/doc/ (ダウンロードするなら「Windows Help (chm)」がオススメ)
✤ 主要ドキュメント: チュートリアル、ライブラリリファレンス、言語仕様リファレンス
✤ コーディング規約✤ PEP 8: Style Guide for Python Code (日本語訳)
http://oldriver.org/python/pep-0008j.html
✤ Google Python スタイルガイド(日本語訳)http://works.surgo.jp/translation/pyguide.html
9
インストールと起動
10
Windows
✤ http://www.python.org/download/releases/2.5.4/ から「python-2.5.4.msi」をダウンロードしてインストール✤ 標準では C:\Python25 にインストールされる✤ 環境変数 %PATH% に C:\Python25 を追加するとよい例: set PATH=%PATH%;C:\Python25
✤ PyScripter(Python用IDE)をインストール http://mmm-experts.com/Products.aspx?ProductId=4 から左メニューの「Download」をクリック
注: Google AppEngine が 2.5 系のため、本稿では 2.5 系列を使う
11
MacOS X
✤ 標準で Python がインストール済み(だけど、バージョンが違う)
✤ MacPorts でインストール
✤ $HOME/.bashrc に「alias py=python」を追加
注: Google AppEngine が 2.5 系のため、本稿では 2.5 系列を使う
$ sudo port install python 25$ sudo python_select python25$ which python/opt/local/bin/python$ python -VPython 2.5.4
12
自前でコンパイル$ wget http://www.python.org/ftp/python/2.5.5/Python-2.5.5.tar.bz2$ tar xjf Python-2.5.5.tar.bz2$ cd Python-2.5.5$ ./configure --prefix=/usr/local/python/2.5.5$ make$ sudo make install$ export PATH=/usr/local/python/2.5.5/bin:$PATH$ which python /usr/local/python/2.5.5/bin/python$ alias py=python$ cat >> $HOME/.bashrcexport $PATH=/usr/local/python/2.5.5/bin:$PATHalias py=python^D
注: Google AppEngine が 2.5 系のため、本稿では 2.5 系列を使う
13
起動
$ python example.py # または py example.py
スクリプト名を指定して起動
$ python # または py
>>> 1 + 12>>> exit() # または Control+D
スクリプト名を指定せずに起動(インタラクティブシェル)
または
$ ipython # より高機能なインタラクティブシェル
14
エラーがあったら
>>> name = "Haruhi">>> namaeTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'namae' is not defined
•エラーが発生したら、いちばん下のメッセージを見ること
ファイル名と行番号
例外クラスとエラーメッセージ
15
主な例外クラス✤ SyntaxError : 文法が間違っている、またはコードに日本語が含まれて
いるのに「# -*- coding: utf-8 -*-」がない✤ NameError : 変数名や関数名を間違えている✤ TypeError : データや引数の数または型が間違っている✤ ValueError : 型は正しいが値として間違っている✤ AttributeError : 属性名やメソッド名を間違えている、
または変数の値がNoneである✤ UnicodeEncodeError : ユニコード関連のエラー✤ KeyError : 辞書のキーが存在しない✤ IndexError : リストやタプルで添字が範囲外✤ IOError : ファイルが存在しない、またはアクセス許可がない✤ ImportError : モジュール名を間違えている
16
サンプルプログラム
【関連ドキュメント】
• チュートリアル: 3. 形式ばらない Python の紹介http://www.python.jp/doc/release/tut/node5.html
17
コメントPHP Python
// 行コメント# 行コメント/* 範囲コメント */
# -*- coding: utf-8 -*-# 行コメント
•「#」が行コメント•範囲コメントはなし•日本語を含める時はマジックコメントが必要
•「//」と「#」が行コメント
•「/* */」が範囲コメント
マジックコメント(「# coding: utf-8」でも可)
18
Hello WorldPHP Python
echo "Hello World!\n"; print "Hello World!"# またはimport syssys.stdout.write( "Hello World!\n")
•「;」が必要ない• print が自動的に改行を出力
•文末に「;」が必要•改行を出力するには「\n」を明示
19
Hello World (2)PHP Python
$name = "World";echo "Hello ", $name, "!\n";echo "Hello $name!";
name = "World"print "Hello", name, "!"print "Hello %s!" % name
•変数に $ をつける•文字列中に変数を埋め込める
•変数に prefixをつけない•文字列中に変数を埋め込めない
20
奇数だけ出力PHP Python
$arr = array(1, 2, 3, 4, 5);foreach ($arr as $item) { if ($item % 2 == 1) { echo $item, "\n"; }}
list1 = [1, 2, 3, 4, 5]for item in list1: if item % 2 == 1: print item
•配列はarray()• foreach や if で () が必要 •ブロックは「{ }」で表現
•リストは []• for や if で () いらず •ブロックは「:」とインデントで表現
21
フィボナッチ数列PHP Python
function fib($n) { return $n <= 2 ? 1 : fib(n-1) + fib(n-2);}echo fib(30);
def fib(n): return 1 if n <=2 else \ fib(n-1) + fib(n-2)
print fib(30)
•関数定義は「function」•条件演算子は
式 ? 真のとき : 偽のとき
•関数定義は「def」•条件演算子は真のとき if 式 else 偽のとき
22
データの中身を表示PHP Python
$val = array( "one"=>1, "two"=>2);var_export($val);
val = { "one":1, "two": 2 }print repr(val)
•連想配列はarray()•データの中身は
var_export() や var_dump() で表示
•辞書は { }•データの中身は repr() で表現 (なしでもよい)
23
メタプログラミングPHP Python
function errmsg($mesg) { $f = fopen("php://stderr", "w"); fwrite($f, $mesg."\n"); fclose($f);}$func = 'errmsg';$func("ERROR");
import syssys.stderr.write("ERROR\n")write = sys.stderr.writewrite("ERROR\n")
x = 1add1 = x.__add__print add1(3) #=> 4
•メソッドを取り出し、変数に代入可能、かつ呼び出し可能
•関数名やメソッド名を表す文字列を変数に代入し、呼び出し可能
24
リテラル
【関連ドキュメント】
• 言語仕様リファレンス: 2.4 リテラル (literal)http://www.python.jp/doc/release/ref/literals.html
• ライブラリリファレンス: 3. 組み込み型http://www.python.jp/doc/release/lib/types.html
25
数値PHP Python
123 # 整数077 #=> 63 0xFF #=> 255 3.14 # 小数1.0e-4 #=> 0.0001
pow(2,64) #=> 1.844674407371E+19
123 # 整数077 #=> 63 0xFF #=> 255 3.14 # 小数1.0e-4 #=> 0.0001 3+4j # 複素数2**64 #=> 18446744073709551616L
26
文字列PHP Python
# メタキャラクタ解釈あり"str\n"
# メタキャラクタ解釈なし'str\n'
# メタキャラクタ解釈あり"str\n"'str\n'
# メタキャラクタ解釈なしr"str\n"r'str\n'
27
複数行文字列PHP Python
# 複数行文字列"aaabbbccc"
'aaabbbccc'
# 複数行文字列"""aaabbbccc"""
r'''aaabbbccc'''
「"」3つまたは「’」3つで囲む
「r」をつけることも可
28
ヒアドキュメントPHP Python
# ヒアドキュメント$string = <<<ENDaaabbbcccEND;
# ヒアドキュメントはなし、# 複数行文字列を使うstring = """aaabbbccc"""[1:]
最初の改行文字を取り除く(詳細は後述)
29
ユニコードPHP Python
# 該当機能なし # -*- coding: utf-8 -*-
"ばけらった" # stru"ばけらった" # unicode
## 変換u"ば".encode('utf8') # str"ば".decode('utf8') # unicode
マジックコメント
•マジックコメントがないとSyntaxError
•「# coding: utf-8」でも可30
真偽値、NULLPHP Python
TRUE # 真FALSE # 偽NULL # NULL
True # 真False # 偽None # NULL
•大文字・小文字の区別なし•偽となるのは FALSE, NULL,
0, 空の文字列や配列
•大文字・小文字の区別あり•偽となるのは False, None, 0, 空の文字列やリストやタプルや辞書
31
演算子
【関連ドキュメント】
• 言語仕様リファレンス: 5. 式 (expression)http://www.python.jp/doc/release/ref/expressions.html
• ライブラリリファレンス: 3. 組み込み型http://www.python.jp/doc/release/lib/types.html
32
同値判定PHP Python
"123" == "123""123" != "123" "0123" == 123 #=> TRUE"0123" === 123 #=> FALSE"0123" === "123" "0123" !=== "123"
"123" == "123""123" != "123""123" == 123 #=> False"123" != "123" u"123" == "123" #=> True
• '==' は文字列が数値に変換されることがある
• '===' は変換せずに比較
•数値と文字列が勝手に変換されることはない
• unicodeは変換される
33
同一判定Python
True == 1 #=> TrueTrue is 1 #=> FalseFalse == 0 #=> TrueFalse is 0 #=> FalseNone == 0 #=> FalseNone is 0 #=> False
• Trueは1と同値かつ非同一、Falseは0と同値かつ非同一
list1 = []list2 = []list1 == list2 #=> Truelist1 is list2 #=> Falselist2 = list1list1 is list2 #=> True
• '==' は同値判定、'is' は同一判定(反対は 'is not')
34
比較演算子PHP Python
1 > 01 >= 10 < 11 <= 1
0 < $x && $x < 3
1 > 01 >= 10 < 11 <= 1
0 < x < 30 < 1 <= 2 == 2 < 3
•複数の比較は && で連結 •複数の比較を連結できる
35
論理演算子PHP Python
! x x && y x and yx || y x or y x xor y
$x = $val or die(); # ($x = $val) or die() と同じ
not xx and yx or y# --
x = val or die() # x = (val or die()) と同じ
•優先度が違う2種類を用意 • '!', '&&', '||' は使えない
36
論理演算子の値PHP Python
10 && 0 #=> FALSE0 || 10 #=> TRUE
$x = $y = "";$v = $x ?: $y ?: "default";
10 and 0 #=> 00 or 10 #=> 10
x = y = ""v = x or y or "default"
•論理演算子の結果は必ずTRUEかFALSE
•論理演算子の結果がTrueやFalseにならない
37
メンバシップPHP Python
# 該当演算子なし 2 in [1, 2, 3] # True4 not in [1, 2, 3] # True"a" in {"a": 10} # True"b" not in {"a": 10} # True"ana" in "banana" # True
• listやtupleやsetの場合は要素が含まれるか?
• dictならキーに含むか?•文字列なら部分文字列か?
38
算術演算子PHP Python
1 + 11 - 11 * 110 / 3 #=> 3.3333333310 % 3 #=> 1pow(2, 10) #=> 1024
1 + 11 - 11 * 110 / 3 #=> 310 % 3 #=> 12**10 #=> 1024
39
結合演算子PHP Python
"foo" . "bar" #=> "foobar" "foo" + "bar" # stru"foo" + u"bar" # unicodeu"foo" + "bar" # unicode"foo" + u"bar" # unicode
•ひとつでもunicodeなら結果もunicode
•すべてstrのときだけ結果もstr
40
代入演算子PHP Python
$x = 1$x += 1$x -= 1$x *= 1$x /= 1$x %= 1$x .= "str"
x = 1x += 1x -= 1x *= 1x /= 1x %= 1x += "str"
41
ビット演算子、シフト演算子PHP Python
$x & 0xFF$x | 0xFF$x ^ 0xFF~ $x
$x << 2$x >> 2
x & 0xFFx | 0xFFx ^ 0xFF~ x
x << 2x >> 2
42
三項演算子(条件演算子)PHP Python
$v = $x > 0 ? $x : - $x;
$v = $x > 0 ? $x : ($y > 0 ? $y : ($z > 0 ? $z : -9999));
v = (x if x > 0 else - x)
v = (x if x > 0 else \ y if y > 0 else \ z if z > 0 else -9999)
• Perlの後置記法と間違えないよう、カッコ推奨
•つなげること自体にはカッコいらず
•演算子優先順位の問題により、つなげるときはカッコが必要
43
その他✤ 演算子オーバーロードが可能✤ x++(インクリメント)や x--(デクリメント)は、ない✤ `shell command` は、ない(import os; os.system("shell command") を使う)
44
コンテナ
【関連ドキュメント】
• チュートリアル: 5. データ構造http://www.python.jp/doc/release/tut/node7.html
• ライブラリリファレンス: 3.6.4 変更可能なシーケンス型http://www.python.jp/doc/release/lib/typesseq-mutable.html
• ライブラリリファレンス: 3.8 マップ型http://www.python.jp/doc/release/lib/typesmapping.html
45
リスト (List)PHP Python
# 配列$arr = array(10, 20, 30,);echo $arr[2];$arr[] = 40;var_export($arr);
# リスト(更新可能)list1 = [10, 20, 30,]print list1[2]list1.append(40)print repr(list1)
•実体は連想配列•最後の ',' は省略可能
•連結リストではない•最後の ',' は省略可能
46
リスト: 代入によるコピーPHP Python
$arr1 = array(10, 20, 30);$arr2 = $arr1;
$arr2[1] = 25;var_export($arr1); #=> array(0=>10, # 1=>20, # 2=>30) # (変更されてない)
list1 = [10, 20, 30]list2 = list1
list2[1] = 25print repr(list1) #=> [10, 25, 30] # (変更された!)
配列がコピーされる 同じリストを共有
•コピーは list2 = list1[:](スライスについては後述)
47
リスト: 繰り返しPHP Python
## 単純ループforeach ($arr as $x) echo $x;## カウンタ付きループforeach ($arr as $i=>$x) echo $i, $x;
## 単純ループfor x in list1: print x## カウンタ付きループfor i, x in enumerate(list1): print i, x
48
リスト: 各種操作Python
## リストの長さlist1 = ['a', 'b', 'c']print len(list1) #=> 3
## 要素が含まれるかどうかprint 'b' in list1 #=> Trueprint 'x' in list1 #=> False
## 要素の連結print "".join(list1) # 'abc'print ",".join(list1) # 'a,b,c'
### 逆順にする (破壊的)list1.reverse()print list1 #=> ['c','b','a']
49
リスト: 各種操作Python
## 要素を追加する (破壊的)list1 = []list1.append(10)list1.append(20)print list1 #=> [10, 20]
## 他のリストを追加 (破壊的)list1.extend([30, 40])print list1 #=> [10, 20, 30, 40]
## 添字を指定して追加 (破壊的)list1.insert(3, 'A')print list1 #=> [10, 20, 30, 'A', 40]
50
リスト: 各種操作Python
## 一致する要素の添字を返すlist1 = ['a','b','c','b']print list1.index('b') #=> 1print list1.index('x') #=> ValueError
## 一致する要素の数を返すprint list1.count('b') #=> 2
51
リスト: 各種操作Python
## 一致する最初の要素を取り除く (破壊的)list1 = [3, 1, 4, 1, 5, 9]list1.remove(1)print list1 #=> [3,4,1,5,9]list1.remove(999) #=> ValueError
## 最後の要素を取り除いて返す (破壊的)print list1.pop() #=> 9print list1 #=> [3,4,1,5][].pop() #=> IndexError
52
リスト: 各種操作Python
## ソート (破壊的)list1 = [3, 1, 4, 1, 5, 9]list1.sort()print list1 #=> [1, 1, 3, 4, 5, 9]
## ソート (非破壊的)list1 = [3, 1, 4, 1, 5, 9]list2 = sorted(list1)print list2 #=> [1, 1, 3, 4, 5, 9]print list1 #=> [3, 1, 4, 1, 5, 9]
## 逆順ソート (破壊的)list1.sort(reverse=True)print list1 #=> [9, 5, 4, 3, 1, 1]
## 要素を指定したソート (破壊的)list2 = [['A',3], ['B',1], ['C',2]]list2.sort(key=lambda x: x[1])print list2 #=> [['B', 1], ['C', 2], ['A', 3]]
53
タプル (Tuple)
✤ タプル (tuple)✤ 変更できないリスト✤ リストより軽量✤ 辞書のキーに指定可能✤ リストと同じ操作が可能(非破壊操作のみ)
Python
# タプル(更新不可)tuple1 = (10, 20, 30)print tuple1[2]tuple1[2] = 31 #=> TypeErrorprint repr(tuple1)
var = (9) # 整数値var = (9, ) # タプルvar = () # 空タプル
54
辞書 (Dictionary)PHP Python
# 連想配列$arr = array("a"=>1, "b"=>2);
echo $arr["b"]; #=> 2$arr["c"] = 3;
var_export($arr); #=> array('a'=>1,'b'=>2,'c'=>3)
# 辞書dict1 = {"a":1, "b":2 } # or dict1 = dict(a=1, b=2)print dict1["b"] #=> 2dict1["c"] = 3
print dict1 # or repr(dict1) #=> {'a': 1, 'c': 3, 'b': 2}
•順番が保存される •順番は保存されない
55
辞書: キーが存在しないときPHP Python
$arr = array('A'=>1, 'B'=>2);echo $arr['A'];echo $arr['X']; #=> NULL
echo isset($arr['X']) ? $arr['X'] : 10;
dict1 = {'A':1, 'B':2}print dict1['A']print dict1['X'] #=> KeyError
print dict1.get('X', 10) #=> 10print dict1.get('X') #=> None
•キーが存在しないときはKeyErrorが発生
• dict.get()でキーがないときのデフォルト値を指定可能
•キーが存在しないときはNULL (Warningも出る)
•キーがないときのデフォルト値を指定する方法なし
56
辞書: 繰り返しPHP Python
foreach ($arr as $key=>$val) echo $key, $val;
foreach ($arr as $item) echo $item; # 値
for key, val in dict1.iteritems(): print key, val
for item in dict1: print item # キー
• dict.iteritems()を使う•使わない場合はキーの繰り返し (dict.iterkeys()推奨)
•「as $key=>$val」ならキーと値の繰り返し
•「as $val」なら値の繰返し
57
辞書: 各種操作Python
## 要素の数dict1 = {'A':1, 'B':2}print len(dict1) #=> 2
## すべてのキーを取り出すprint dict1.keys() #=>['A','B']
## すべての値を取り出すprint dict1.values() #=> [1,2]
## キーが存在するかどうかprint dict1.has_key('A')print 'A' in dict1
## 要素を削除 (破壊的)del dict1['A']print dict1 #=> {'B':2}del dict1['C'] #=> KeyError
58
辞書: 各種操作Python
## コピーdict1 = {'A': 1, 'B': 2}dict2 = dict1.copy()print dict2 #=> {'A': 1, 'B': 2}
## 別の辞書で更新 (破壊的)dict2.update({'C':3})print dict2 #=> {'A': 1, 'C': 3, 'B': 2}
## キーを指定して削除 (破壊的)print dict2.pop('C') #=> 3print dict2.pop('C') #=> KeyErrorprint dict2.pop('C', 3) #=> 3
## すべてを削除 (破壊的)dict2.clear()print dict2 #=> {}
59
辞書: 各種操作Python
## キーがないときだけ値を追加dict1 = {'A':1, 'B':2}dict1.setdefault('C', 3) # 'C' はないので追加され、かつ 3 が返されるdict1.setdefault('C', 9) # 'C' はあるので追加されず、かつ # dict['C'] が返される## 使い道:たとえばこれがif 'key' not in dict1: dict1['key'] = []dict1['key'].append('val')## こう書けるdict1.setdefault('key', []).append('val')
60
集合 (Set)
✤ set ✤ 値の集まり✤ 順序を持たない✤ 値の重複を許さない✤ 変更可能✤ 辞書のキーに指定可能な値のみ受け付ける
✤ frozenset ✤ 変更不可なset✤ 辞書のキーに指定可能
Python
# 集合 (set)set1 = set(['a', 'b'])print set1 #=> set(['a', 'b']) # 順序を持たないset1.add('c')print set1 #=> set(['a', 'c', 'b'])# 値の重複を許さない set1.add('a')print set1 #=> set(['a', 'c', 'b'])
リストや辞書は不可
61
集合: よくある例Python
## リストを使った判定(遅い)members = ['Haruhi', 'Mikuru', 'Yuki', 'Itsuki', 'Kyon']for i in xrange(10000): found = 'Tsuruya' in members
## 集合を使った判定(速い)members = set(['Haruhi', 'Mikuru', 'Yuki', 'Itsuki', 'Kyon'])for i in xrange(10000): found = 'Tsuruya' in members
62
集合: 各種操作Python
## 値を追加set1 = set(['a', 'b', 'c'])set1.add('d')
## 値を削除set1.remove('d')set1.remove('d') #=> KeyErrorset1.discard('d') # 値がなくても # 例外を投げない## 要素数print len(set1) #=> 3
## 値があるかどうか'a' in set1 #=> True'A' not in set2 #=> True
## 繰り返しfor x in set1: print x, #=> a c b
## 浅いコピーset2 = set1.copy()
63
集合: 各種演算Python
set1 = set(['a', 'b'])set2 = set(['b', 'c'])## 和集合 (∪)set1 | set2 #=> set(['a','b','c'])## 積集合 (∩)set1 & set2 #=> set(['b'])## 差集合 (∪)set1 - set2 #=> set(['a'])## 対象差 (△)set1 ^ set2 #=> set(['a','c'])
## 包含関係 (⊆、⊇)set3 = set(['a', 'b', 'c'])set4 = set(['b', 'c'])set3 > set4 #=> Trueset3 < set4 #=> Falseset3 >= set4 #=> Trueset3 <= set4 #=> Falseset3 > set3 #=> Falseset3 < set3 #=> Falseset3 >= set3 #=> Trueset3 <= set3 #=> True
64
シーケンス、スライス
【関連ドキュメント】
• ライブラリリファレンス: 3.6 シーケンス型 str, unicode, list, tuple, buffer, xrangehttp://www.python.jp/doc/release/lib/typesseq.html
• 言語仕様リファレンス: 3 スライス表記 (slicing)http://www.python.jp/doc/release/ref/slicings.html
65
シーケンスとは?✤ (主に) リスト、タプル、文字列のこと✤ どれも同じような操作を提供
Python
L = ['a', 'b', 'c', ] # リストT = ('a', 'b', 'c', ) # タプルS = "abc" # 文字列
# 要素へのアクセスprint L[2], T[2], S[2] #=> c c c
# 要素の繰り返しfor x in L: print x, #=> a b cfor x in T: print x, #=> a b cfor x in S: print x, #=> a b c
66
シーケンス: 操作Python
# 要素があるかどうかprint 'b' in Lprint 'b' in Tprint 'b' in S
# 要素が含まれないかprint 'x' not in Lprint 'x' not in Tprint 'x' not in S
# 結合print L + ['d'] #=> ['a','b','c','d']print T + ('d',) #=> ('a','b','c','d')print S + "d" #=> 'abcd'
# 長さprint len(L) #=> 3print len(T) #=> 3print len(S) #=> 3
67
シーケンス: 変換Python
# リストへ変換print list(T) #=> ['a', 'b', 'c']print list(S) #=> ['a', 'b', 'c']
# タプルへ変換print tuple(L) #=> ('a', 'b', 'c')print tuple(S) #=> ('a', 'b', 'c')
# 文字列へ変換print str(L) #=> "['a', 'b', 'c']"print str(T) #=> "('a', 'b', 'c')"
# 要素を連結print "".join(L) #=> 'abc'print "".join(T) #=> 'abc'
68
スライス: 部分要素の取り出しPython
# -5 -4 -3 -2 -1# 0 1 2 3 4L = ['a','b','c','d','e'] # リストT = ('a','b','c','d','e') # タプルS = "abcde" # 文字列
# 部分要素の取り出しprint L[1:3] #=> ['b', 'c']print T[1:3] #=> ('b', 'c')print S[1:3] #=> 'bc'print L[1:-1] #=> ['b', 'c', 'd']print T[1:-1] #=> ('b', 'c', 'd')print S[1:-1] #=> 'bcd'• L[1:3] なら L[1] と L[2] は含
まれるが L[3] は含まれないことに注意
• L[n:m] の長さは m-n•マイナスは後ろから数える
69
スライス: 部分要素の変更Python
# 部分要素の変更L = ['a', 'b', 'c', 'd', 'e']print L[1:3] #=> ['b', 'c']L[1:3] = ('X', 'Y', 'Z')print L #=> ['a', 'X', 'Y', 'Z', 'd', 'e']
型や要素数が異なっていてもよい
•タプルと文字列は変更不可 (immutable) なので、TypeError になる
70
スライス: 添字省略時Python
# 0 1 2 3 4L = ['a', 'b', 'c', 'd', 'e']print L[:2] #=> ['a', 'b']print L[2:] #=> ['c', 'd', 'e']print L[:] #=> ['a','b','c','d','e']
•最初の添字を省略すると 0•最後の添字を省略すると len(L)
L == L[:n] + L[n:] # 常に真
L2 = L[:] # 全体のコピー
L3 = L # 同じリストを共有
71
文字列操作
【関連ドキュメント】
• ライブラリリファレンス: 3.6.1 文字列メソッドhttp://www.python.jp/doc/release/lib/string-methods.html
• チュートリアル: 3.1.2 文字列http://www.python.jp/doc/release/tut/node5.html#SECTION005120000000000000000
72
文字列操作Python
# 単純結合'Ha'+'ru'+'hi' #=> 'Haruhi'
# 複数文字列結合''.join(['s', 'o', 's']) #=> 'sos''/'.join(['s','o','s']) #=> 's/o/s'
# 繰り返し'Wa' * 3 #=> 'WaWaWa'
# 部分文字列"Haruhi"[2:5] #=> 'ruh'
# 長さlen("Suzumiya") #=> 8
# 数値に変換int("10") #=> 10int("FF", 16) #=> 255 (16進数)float("3.14") #=> 3.1400000001
73
文字列操作Python
# 書式 (printf相当)x, y = 'A', 123'x=%s, y=%s' % (x, y) # x=A, y=123'<%5s>' % x # < A>'<%-5s>' % x # <A >'<%5d>' % y # < 123>'<%-5d>' % y # <123 >'<%05d>' % y # <00123>
'pi=%f' % 3.1415 # pi=3.141500'pi=%7.3f' % 3.1415 # pi= 3.142'list=%r' % [10,20,30] # list=[10, 20, 30]'dict=%r' % {'a':10} # dict={'a': 10}'a=%(a)s, b=%(b)s' % {'a':10,'b':20} # x=10, y=20'x=%(x)s, y=%(y)s' % locals() # x=A, y=123
値が複数ならタプルで指定
74
文字列操作Python
# 部分文字列を検索"Haruhi".find("uh") #=> 3"Haruhi".find("x") #=> -1"Haruhi".index("uh") #=> 3"Haruhi".index("x") #=> ValueError
# 逆から検索"Mikuru".rfind("u") #=> 3"Mikuru".rindex("u") #=> 5
# 開始文字列をチェック'Nyoroon'.startswith('Nyo') #=> True# 終了文字列をチェック'Dounyoro'.endswith('nyoro') #=> True
75
文字列操作Python
# 置換"Mikuru".replace('ku', 'chi') #=> 'Michiru'# カウント'kamadouma'.count('ma') #=> 2# 空白文字の削除" Kyon ".strip() #=> 'Kyon'" Kyon ".lstrip() #=> 'Kyon '" Kyon ".rstrip() #=> ' Kyon'
# 行に分割s = """HaruhiMikuruYuki"""s.splitlines() #=> ['Haruhi', 'Mikuru', 'Yuki']s.splitlines(True) #=> ['Haruhi\n', 'Mikuru\n', 'Yuki\n']
76
文字列操作Python
# 大文字に変換"yuki".upper() #=> "YUKI"
# 小文字に変換"YUKI".lower() #=> "yuki"
# 大文字・小文字を入れ替える"Yuki".swapcase() #=> 'yUKI'
# 文字種類の判別"Endless8".isalnum() #=> True"Endless8".isalpha() #=> False"8".isdigit() #=> True"endless8".islower() #=> True"ENDLESS8".isupper() #=> True" ".isspace() #=> True"End Less Eight".istitle() #=> True
77
文字列操作Python
# キャピタライズ'yuki'.capitalize() #=> Yuki
# 単語ごとにキャピタライズ"haruhi mikuru YUKI".title() #=> 'Haruhi Mikuru Yuki'
# 中央揃え'Kyon'.center(10) #=> ' Kyon ' (長さ10)
# 文字列幅の調整"Yuki".ljust(8, '!') #=> 'Yuki!!!!'"Yuki".rjust(8, '!') #=> '!!!!Yuki'
# 頭にゼロを追加'8'.zfill(3) #=> '008'
# タブを半角空白に展開"Nyo\troon".expandtabs(8) #=> 'Nyo roon'
78
基本構文
【関連ドキュメント】
• チュートリアル: 4. その他の制御フローツールhttp://www.python.jp/doc/release/tut/node6.html
• 言語仕様リファレンス: 6. 単純文 (simple statement)http://www.python.jp/doc/release/ref/simple.html
• 言語仕様リファレンス: 7. 複合文 (compound statement)http://www.python.jp/doc/release/ref/compound.html
79
print文PHP Python
$x = 10; $y = 20;echo 'x=', $x, ', y=', $y, "\n";echo "x=$x, y=$y\n";
x = 10; y = 20print 'x=', x, ', y=', yprint 'x=%s, y=%s' % (x, y)
•改行は"\n"で明示•引数間に空白は入らない
•自動的に改行される("," で終わると改行しない)
•引数間に半角空白が入る
80
代入文PHP Python
$x = 0;
$x += 1;
$x++;
# 多重代入list($x, $y) = array(10, 20);list($x, $y) = array($y, $x);
x = 0
x += 1
# インクリメントはなし
# 多重代入x, y = 10, 20 # or (10,20)x, y = y, x # or (y, x)
81
if文PHP Python
$x = 0;if ($x > 0) { echo "$x is positivie.\n";} elseif ($x < 0) { echo "$x is negative.\n";} else { echo "$x is zero.\n";}
x = 0if x > 0: print "%s is positive." % xelif x < 0: print "%s is negative." % xelse: print "%s is zero." % x
82
while文PHP Python
$i = 0;while (++$i <= 10) { echo $i, "\n";}
i = 1while i <= 10: print i i += 1
• do { } while () も利用可能
• do - while は、なし
83
for文PHP Python
$arr = array(10, 20, 30);foreach ($arr as $item) { echo $item, "\n";}
for ($i=0; $i<10; $i++) { echo $i, "\n";}
list1 = [10, 20, 30]for item in list1: print item
for i in xrange(1, 10): print i
• for (;;) はないので、xrange()で代用 (後述)• for (;;) も利用可能
84
break文、continue文PHP Python
foreach ($arr as $item) { if ($item === NULL) continue; if ($item === 100) { echo "found!\n"; break; }}
for item in list1: if item is None: continue if item == 10: print "found!" break
85
pass文PHP Python
if (! $name) { // TODO: エラー処理
} else { echo $name;}
if not name: ## TODO: エラー処理 passelse: print name
•何もしないことを表すためにpass文が必要
86
del文PHP Python
$x = 1;echo $x; #=> 1unset($x);echo $x; # Notice: undefined variable$arr = array("a"=>123);echo $arr["a"]; #=> 123unset($arr["a"]);echo $arr["a"] # Notice: Undefined index
x = 1print x #=> 1del xprint x # NameError
dict1 = {"a":123}print dict1["a"] #=> 123del dict1["a"]print dict1["a"] # KeyError
87
else節PHP Python
$arr = array(1, 2, 3);$found = FALSE;foreach ($arr as $item) { if ($item == 100) { $found = TRUE; break; }}if (! $found) echo "not found\n";
list1 = [1, 2, 3]for item in list1: if item == 100: breakelse: print "not found"
• forとwhileにelse節を追加できる
• breakしなかったときだけelse節を実行
88
try文PHP Python
try { throw new Exception("msg");} catch (Exception $ex) { echo $ex->message();} catch (OtherException $ex) { throw $ex;}
try: raise Exception("msg")except Exception, ex: print ex.messageexcept OtherException, ex: raisefinally: print "finally"
• finally節が利用可能
89
assert文PHP Python
$var = NULL;assert('$var != NULL');
var = Noneassert var != None# これは次と同等if __debug__: if not (var != None): raise AssertionError
• assert 文の引数は、式そのもの
• Python起動時に -O を指定すると無視される
• assert関数の引数は、式を表す文字列
• assert_option() で挙動を指定できる
90
with文Python
from __future__ \ import with_statementwith open('file.txt') as f: for line in f: print line,## with文が終了した時点で## fが自動的にクローズされる
## これは次と(だいたい) 同じf = open('file.txt')f.__enter__()try: for line in f: pirnt line,finally: f.__exit__()
内部でf.close()を実行•参照: PEP 0343 The "with" statementhttp://www.python.org/peps/pep-0343.html
Python2.5では必要
91
内包表記 (list complehension)Python
list1 = [1, 2, 3, ]list2 = [ i*i for i in list1 ]print list2 #=> [1, 4, 9]
## これは次と同等list2 = []for i in list1: list2.append(i*i)
list2 = [ i*i for i in list1 if i % 2 == 1 ]print list2 #=> [1, 9]
## これは次と同等list2 = []for i in list1: if i % 2 == 1: list2.append(i*i)
• for文より簡潔で高速でわかりやすい• for文は動作の記述、内包表記は意図の記述
92
関数
【関連ドキュメント】
• チュートリアル: 4.7 関数定義についてもう少しhttp://www.python.jp/doc/release/tut/node6.html#SECTION006700000000000000000
• ライブラリリファレンス:2.1 組み込み関数http://www.python.jp/doc/release/lib/built-in-funcs.html
• 言語仕様リファレンス: 7.6 関数定義http://www.python.jp/doc/release/ref/function.html
93
関数定義PHP Python
/** フィボナッチ数を計算 */function fib($n) { if ($n <= 2) { return 1; } else { return fib($n-1)+fib($n-2); }}
echo fib(30);
def fib(n): """フィボナッチ数を計算""" if n <= 2: return 1 else: return fib(n-1)+fib(n-2)
print fib(30)help(fib)
ドキュメントを表示
関数定義の冒頭に記述(構文としてサポート)
94
引数のコピーPHP Python
function f($arr) { $arr[0] = 123; var_export($arr);}$arr = array(10);f($arr); #=> array(0=>123,)var_export($arr); #=> array(0=>10, )
def f(list1): list1[0] = 123 print repr(list1)
list1 = [10]f(list1) #=> [123]print repr(list1) #=> [123]
•引数の配列はコピーされる•引数のリストや辞書はコピーされない
95
デフォルト引数PHP Python
function f($x, $y=0, $z=0) { echo $x, $y, $z;}
function g($a=array()) { $a[] = 1; var_export($a);}g(); g(); g();
def f(x, y=0, z=0): print x, y, z
def g(a=[]): a.append(1) print repr(a)
g(); g(); g()
同じリストが毎回使われる新しい配列が
毎回作成される
96
キーワード引数PHP Python
## 該当機能なし ## 仮引数の名前を使って## 実引数を指定するdef f(x, y=0, z=0): return x + y + z
## どれも f(5, 0, 10) と同じprint f(5, z=10)print f(z=10, x=5)
97
可変長引数PHP Python
function f() { $args = func_get_args(); var_export($args);}f(10, "A", TRUE);## 実行結果array (0 => 10, 1 => 'A', 2 => true,)
def f(*args, **kwargs): print repr(args) # タプル print repr(kwargs) # 辞書
f(10, "A", True, x=30, y=40)## 実行結果(10, 'A', True){'y': 40, 'x': 30}
98
可変長引数:サンプルPython
def img(src, **attrs): html = '<img src="%s" ' % src for k, v in attrs.iteritems(): html += ' %s="%s" ' % (k, v) html += ' />' return html
print img('logo.gif', id='logo_gif', alt='logo image') #=> <img src="logo.gif" alt="logo image" id="logo_gif" />
普通の引数と可変長引数とが混在可能
99
関数オブジェクトPHP Python
## 該当機能なし def f(a, b): return a+b;g = f # 関数を代入print g(2, 3) #=> 5print dir(g) # 属性を表示 print g.func_name #=> f
•「関数を定義する」=「関数オブジェクトを作成し変数に代入する」
•関数もデータである
100
無名関数PHP Python
## その場で関数を作成$f = create_function( '$a, $b', 'return $a+$b;' );
echo $f(10, 20); #=> 30var_export($f); #=> 'lambda_1'
## その場で関数を作成f = lambda a, b: a + b## これは次とほぼ同じ## def f(a, b): return a+b
print f(10, 20) #=> 30print f.func_name #=> '<lambda>'
•本体は式のみ(文は不可)•本体を文字列で指定(< PHP5.3)
101
関数の再定義PHP Python
function f(x){ return x+x;}function f(x) { #=> Fatal Error return 2*x;}
def f(x): return x+x
def f(x): return 2*x
•関数の再定義は、「変数への再代入」でしかない
•同名の関数を再定義できない
102
関数オブジェクト:サンプルPHP Python
function sigma($x, $y, $f) { $sum = 0; for ($i=$x; $i<=$y; $i++) $sum += $f($i); return $sum;}function pow2($n) { return $n*$n;}sigma(1, 10, "pow2");
def sigma(x, y, f): sum = 0 for i in xrange(x, y+1): sum += f(i) return sum
def pow2(n): return n*n
sigma(1, 10, pow2)文字列で指定
関数オブジェクトを指定
103
変数のスコープPHP Python
list($x, $y, $z)=array(1,2,3);function f() { $x = 7; # local var global $y; $y = 9; # global var echo $z; # undefined var}f()echo "$x $y $z\n"; #=>1 9 3
x, y, z = 1, 2, 3 # globaldef f(): x = 7 # local var global y y = 9 # global var print z # global var
f()print x, y, z #=> 1 9 3
•参照は何もしなくても可•代入はglobal宣言が必要
•参照にも代入にもglobal宣言が必要
104
関数内関数PHP Python
function g($x, $y) { return ($x+$y)*($x-$y);}function f($a, $b, $c, $d) { return g($a, $b) + g($c, $d);}## (2+3)*(2-3) + (4+5)*(4-5)print f(2, 3, 4, 5)
def f(a, b, c, d): def g(x, y): return (x+y)*(x-y) return g(a, b) + g(c, d) ## (2+3)*(2-3) + (4+5)*(4-5)print f(2, 3, 4, 5)
• g() はグローバル(誰でもアクセス可)
• g() はローカル(f() の外からは見えない)
105
組み込み関数Python
len(seq) # 長さを求めるrepr(val) # val の文字列表現を返すrange(start, end, step) # startからend-1までのリストを返すxrange(start, end, step) # range() のイテレータ版sorted(seq) # ソートした新しいseqを返すsum(seq) # seqに含まれる数値を合計するvars(obj) # obj.__dict__ と同じiter(obj) # obj.__iter__() と同じ
106
組み込み関数 (cont)Python
id(obj) # オブジェクトIDを返すglobals() # グローバル変数を表す辞書を返すlocals() # ローカル変数を表す辞書を返す dir(obj) # 属性名の一覧 getattr(obj, name) # 属性値を取り出すsetattr(obj, name, val) # 属性値を設定するdelattr(obj, name) # 属性を削除する
•詳しい一覧は http://www.python.jp/doc/release/lib/built-in-funcs.html
107
モジュール、パッケージ
【関連ドキュメント】
• チュートリアル: 6. モジュールhttp://www.python.jp/doc/release/tut/node8.html
• 言語仕様リファレンス: 6.12 import 文http://www.python.jp/doc/release/ref/import.html
108
モジュールとは?✤ ライブラリファイルのこと✤ 実体はただのPythonスクリプト
util.py
PI = 3.14def add(x, y): return x+ydef sub(x, y): return x-ydef _debug(s): return "*** "+repr(s);
109
importmain.py
import utilprint util #=> <module 'util' from 'util.pyc'>print util.PI #=> 3.14print util.add(10, 20) #=> 30print util.sub(10, 20) #=> -10print util._debug(123) #=> *** 123
•パッケージ名を接頭辞につけてアクセスする必要がある
•実際には、変数utilにモジュールオブジェクトが代入されるだけ
110
frommain.py
from util import PI, addprint PI #=> 3.14print add(10, 20) #=> 30print sub(10, 20) #=> NameError: name 'sub' is not defindprint util.sub(10, 20) #=> NameError: name 'util' is not defined
from util import *print sub(10, 20) #=> -10print _debug(123) #=> NameError: name '_debug' is not defined
必要なものだけimport可能
すべてをimportする、ただし '_' 始まりは除く
• PI = util.PI と同等•変数 util は定義されない
111
注意main.py
import util # OKfrom util import add # OKimport util.add # ImportError
• from がないときは、import の引数はモジュール名でなくてはいけない (関数名などは指定できない)
112
__all__util.py main.py
__all__ = ('PI', 'add')PI = 3.14def add(x, y): return x+ydef sub(x, y): return x-y
from util import *print PIprint add(10, 20)print sub(10, 20) #=> NameErrorfrom util import subprint sub(10, 20) #=> -10
•「import *」したときに読み込まれる変数や関数の名前を列挙する
• __all__ に列挙されてなくても、明示的にimportすることが可能
113
asmain.py
import util as utilityprint utility.add(10, 20)from util import add as plus, sub as minusprint plus(10, 20)
try: import cStringIO as StringIO # C実装版があればそれを使うexcept ImportError: import StringIO # なければ pure Python 版を使う
名前を変えてimport可能
• StringIO = cStringIO と同等
114
__name__util.py
print __name__ #=> util (または main )
def add(x, y): return x+y
if __name__ == '__main__': assert add(10, 20) == 30
自分のパッケージ名を表す特殊変数
•他からimportされたときは "util" に•そうでなければ "__main__" に
コマンドラインでutil.pyが指定されたときだけ実行
115
変数のスコープfoo.py main.py
X = 10 # モジュールローカルdef set_x(x) global X X = x
import foofrom foo import Xprint X # モジュールローカルX = 20print X, foo.X #=> 20 10
foo.set_x(30)print X, foo.X #=> 20 30
• Pythonの「global」はモジュールローカル
これは X = foo.X 相当
foo.X は変更されない
X は変更されない
116
__builtin__パッケージpython python
import __builtin__## 組み込みの関数や## クラスの一覧print dir(__builtin__)## またはfor k in dir(__builtin__): v = getattr(__builtin__, k) print v
def h(s): s = s.replace('&', '&') s = s.replace('<', '<') s = s.replace('>', '>') return s
__builtin__.h = h
• __builtin__は組み込み関数などが入っているパッケージ
• PHPでいう「グローバル」は、Pythonでは「組み込み」(= __builtin__ に登録した)
可能だが非推奨!!
117
パッケージとは?✤ 複数のモジュールを集めたディレクトリ✤ __init__.py が必要
(中身は空でよい)✤ ディレクトリは入れ子可能
mypkg/__init__.py
mypkg/mod1.py
## 中身は空でよい
def add(x, y): return x+y
mypkg/mod2.py
def sub(x, y): return x-y
118
パッケージのimportmain.py
import mypkgprint mypkg #=> <module 'mypkg' from 'mypkg/__init__.py'>print mypkg.mod1 #=> AttributeError: 'module' object has no attribute 'mod1'
パッケージをimportするとmypkg/__init__ モジュールがimportされる
サブモジュールが自動的にimportされるわけではない
119
サブモジュールの importmain.py
import mypkg.mod1
print mypkg #=> <module 'mypkg' from 'mypkg/__init__.pyc'>
print mypkg.mod1 #=> <module 'mypkg.mod1' from 'mypkg/mod1.pyc'>
print mod1 #=> NameError: name 'mod1' is not defined
サブモジュールは '.' で区切る
親モジュールがインポートされる
サブモジュールがインポートされる
パッケージ名が必要
120
サブモジュールの from importmain.py
from mypkg import mod1, mod2print mod1 #=> <module 'mypkg.mod1' from 'mypkg/mod1.pyc'>
from mypkg import mod1 as m1, mod2 as m2print m1 #=> <module 'mypkg.mod1' from 'mypkg/mod1.pyc'>
パッケージ名なしでアクセス可能(mod1 = mypkg.mod1 と同等)
別名でimport可能
121
サブモジュールの import *mypkg/__init__.py
import mod1, mod2__all__ = ('mod1', )
main.py
from mypkg import *print mod1 #=> <module 'mypkg.mod1'>print mod2 #=> NameError
import mypkgprint mypkg.mod1 #=> <module 'mypkg.mod1'>print mypkg.mod2 #=> <module 'mypkg.mod1'>
122
標準添付モジュール✤ sys … システムまわり✤ os … OSやファイルシステム✤ os.path … ファイルパス✤ time … 時刻関連✤ re … 正規表現✤ __builtin__ … 組込の関数やクラスが定義されている
参考: ライブラリインデックスhttp://www.python.jp/doc/release/lib/lib.html
123
その他✤ 検索パスはリスト sys.path に格納されている
✤ 環境変数 $PYTHONPATH を設定すると、sys.path に追加される
import syssys.path.append("lib") # 末尾に追加sys.path.insert(0, "lib") # 先頭に追加
124
オブジェクト指向
【関連ドキュメント】
• チュートリアル: 9. クラスhttp://www.python.jp/doc/release/tut/node11.html
• 言語仕様リファレンス: 7.7 クラス定義http://www.python.jp/doc/release/ref/class.html
125
クラスとコンストラクタPHP Python
class User { var $name; function __construct($name) { $this->name = $name; }}
class User(object): def __init__(self, name): self.name = name
•親クラスとして object を必ず指定すること!
•コンストラクタは__init__()、第1引数はselfを指定すること!
•コンストラクタは__construct()
•インスタンスを表す疑似変数は$this
126
インスタンスオブジェクトPHP Python
$u = new User("Haruhi");echo $u->name;$u->name = "Suzumiya";$u->age = 16; # OKvar_export($u);
u = User("Haruhi")print u.nameu.name = "Suzumiya"u.age = 16 # OKprint u.__dict__ # or vars(u)
•クラスを関数のように呼び出して生成
•未定義のインスタンス変数に代入可能
• new演算子で生成•未定義のインスタンス変数に代入可能
127
インスタンスメソッドPHP Python
class User { var $name; function hello() { echo "Hello $this->name!"; }}$u = new User();$u->name = "Haruhi";$u->hello(); #=> Hello Haruhi!
class User(object): def hello(self): print "Hello %s!" % self.name
u = User()u.name = "Haruhi"u.hello() #=> Hello Haruhi!
•予約語 def で定義•第1引数は必ずselfを指定•予約語 function で定義
128
継承PHP Python
class Animal { function __construct($name) { $this->name = $name; }}class Dog extends Animal { function __construct($name) { parent::__construct($name); }}
class Animal(object): def __init__(self, name): self.name = name
class Dog(Animal): def __init__(self, name): Animal.__init__(self, name)
•親クラスのコンストラクタを呼び出す (必要なら)
•親クラスのコンストラクタを呼び出す (必要なら)
129
superPHP Python
class Dog extends Animal { function bark() { parent::bark(); }}
class Dog(Animal): def bark(self): super(Dog, self).bark() # or Animal.bark(self)
•組み込み関数super()を使って呼び出す
•クラス名を指定する必要がある (←ダサい)
•「parent::」で親クラスのメソッドを呼び出す
•クラス名を指定する必要がない
130
多重継承PHP Python
## なし、## インターフェースで代用
class Animal(object): def bark(self): print "Bow wow"class Entity(object): def save(self): print "insert into ..."class Dog(Animal, Entity): pass
131
isinstancePHP Python
$u instanceof User
$u instanceof User ||$u instanceof Animal
isinstance(u, User)
isinstance(u, (User, Animal))
• instanceof は演算子
• isinstance() は組込関数•タプルを使って複数のクラスを指定可能
132
アクセス制限PHP Python
public class User { private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; }}
class User(object): def __init__(self, name): self._name = name self.__name = nameu = User("Haruhi")print u.__dict__ #=> {'_name': 'Haruhi', # '_User__name': 'Haruhi'}
• '_' で始まっていれば非public•紳士協定であり強制力はない• '__' で始まるとクラス名が自動付加 (Name Mangling)
• 'public'、'protected'、 'private' が利用可能
133
クラス変数、クラスメソッドPHP Python
class User { static $table = "users"; function find($id) { $t = User::$table; echo "select from $t ..."; }}User::find(123);
class User(object): table = "users" @classmethod def find(cls, id): t = cls.table print "select from %s ..." % t
User.find(123)
•デコレータを使う (後述)•第1引数はクラスオブジェクト
•予約語「static」を使う•「$this」にアクセスできないメソッド
134
インスタンスからクラスを参照PHP Python
class User { static $table = "users"; function m1() { echo static::$table; }}$user = new User();$user->m1(); #=> users
class User(object): table = "users" def m1(self): print self.__class__.table
user = User()user.m1() #=> users
•クラスオブジェクトの属性として参照
•「static::」または「self::」をつける
135
スタティックメソッドPython
class Foo(object): @staticmethod def hello(name='World'): print 'Hello %s!' % name
Foo.hello("Mikuru") #=> Hello Mikuru!obj = Foo()obj.hello("Yuki") #=> Hello Yuki!
•クラスからもインスタンスからも呼び出せる•インスタンス変数やクラス変数にはアクセス不可
136
アクセッサPython
class User(object): def __init__(self, name): self.__name = name def _getname(self): return self.__name def _setname(self, name): msg = "'name' is read-only" raise TypeError(msg) name = property(_getname, _setname)
u = User("Yuki")print u.__dict__ #=> {'_User__name': 'Yuki'}print u.name #=> Yukiu.name = "Nagato" #=> TypeError: 'name' is read-only
name属性は読み取り専用になっている
• property() に getter と setter を指定する
137
型(type)Python
type("foo") #=> <type 'str'>
isinstance("foo", str) #=> Trueisinstance(u"f", unicode) #=> Trueisinstance([1, 2], list) #=> Trueisinstance({'a':1}, dict) #=> True
isinstance(val, (tuple, list))isisntance(val, (str, unicode)) # or isinstance(val, basestring)
• list や str は、クラスに似た「型(type)」である•「型」は組み込み関数 type() で取り出せる
138
インスタンスとクラスの仕組み
【関連ドキュメント】
• チュートリアル: 9. クラスhttp://www.python.jp/doc/release/tut/node11.html
• 言語仕様リファレンス: 7.7 クラス定義http://www.python.jp/doc/release/ref/class.html
139
オブジェクト指向言語の仕組み
Variable
Instance obj
Class obj
Class obj
x: 10y: 20
Method Tbl
Method Tbl
m4
m2m3
m3
m1m2
func ( ) { .....}
Z: 123
Z: 456
Function
func ( ) { .....}
func ( ) { .....}
self
self
self
140
インスタンスとクラスの関係
x: 10y: 20
z: 30g: <func>
f: <func>g: <func>
変数 インスタンス
辞書
辞書
辞書
クラス
クラス
.__dict__.__class__ .__dict__
.__base__
object
141
インスタンスとクラス変数Python
class User(object): name = "SOS" def hello(self): print self.name
print User.name #=> SOSprint User.hello #=> <unbound method User.hello>u = User()print u.nameprint u.hello #=> <bound method User.hello of ...>
•インスタンスメソッドはクラス属性
インスタンスと結びついている
インスタンスと結びついてない
142
インスタンスとクラス変数Python
class User(object): name = "SOS"
user = User()print user.name #=> SOS
user.name = "Haruhi"print user.name #=> Haruhi
delattr(user, 'name')print user.name #=> SOS
インスタンス変数が未設定のときはクラス変数の値が使われる
インスタンス変数はクラス変数より優先される
インスタンス変数を削除すると元に戻る
143
bound / unbound メソッドPython
class User(object): def hello(self): print self.name
u = User()u.name = "Kyon"u.hello() #=> KyonUser.hello(u) #=> Kyon
f = u.hello; f() #=> Kyon
• u.hello() と User.hello(u) は (ほぼ) 同等
• u.hello() は bound メソッドの呼び出し
• User.hello() は unbound メソッドの呼び出し、第1引数に self が必要
• bound メソッドは変数に代入して呼び出すことが可能
144
関数とインスタンスメソッドPython
def hello(self): print self.nameprint hello #=> <function hello>
class User(object): passUser.hello = helloprint User.hello #=> <unbound method User.hello>u = User()print u.hello #=> <bound method User.hello>
普通の関数をクラス属性に代入するだけで、インスタンスメソッドとして利用可能
これは普通の関数
145
インスタンスごとのメソッドPython
def hello(self): print self.name
class User(object): pass
•そのインスタンスだけのメソッドを設定するには、 bound method を設定するだけでよい
• types.MethodType でラップすると bound method を生成できる
import typesu = User(); u.name = "Mikuru"u.hello = types.MethodType(hello, u)print u.hello #=> <bound method>u.hello() #=> Mikuru
146
__slots__Python
class User(object): __slots__ = ('name', 'age') def hello(self): print "Hello %s!" % self.name
u = User()u.name = "Haruhi"u.hello() # Hello Haruhi!u.phone = "090-..." # AttributeErrorprint u.__dict__ # AttributeError
• __slots__ に指定した属性のみ利用可能、それ以外はAttributeError
•デフォルト値としてのクラス属性は参照されなくなる
•インスタンスはdictベースではなく構造体ベースになる
•子クラスには引き継がれない
147
ファイル操作
【関連ドキュメント】
• チュートリアル: 7.2 ファイルを読み書きするhttp://www.python.jp/doc/release/tut/node9.html#SECTION009200000000000000000
• ライブラリリファレンス: 3.9 ファイルオブジェクトhttp://www.python.jp/doc/release/lib/bltin-file-objects.html
148
ファイルを読み込むPHP Python
$f = fopen("a.txt", "r");echo fread($f, filesize("a.txt"));fclose($f);
echo file_get_contents("a.txt");
f = open("a.txt")print f.read()f.close()
print open("a.txt").read()
with open("a.txt") as f: print f.read()
CPythonのGCはリファレンスカウント方式なので、参照されなくなったファイルオブジェクトは自動的にcloseされる with文を使うとより安全
149
ファイルに書き込むPHP Python
$f = fopen("file.txt", "w");fwrite($f, "ABC");fclose($f);
file_puts_contents("file.txt", "ABC");
f = open("file.txt", "w")f.write("ABC\n")f.close()
open("file.txt", "w").write( "ABC")
with open("file.txt", "w") as f: f.write("ABC")
with文を使うとより安全
150
文字コードを指定して読み書きPython
import codecsf = codecs.open("file.txt", encoding="utf8")x = f.read() # strではなくunicodeを返すprint type(x) #=> <type 'unicode'>s = x.encode('utf8') # unicodeをstrへ変換f.close()
151
1行ずつ読み込むPHP Python
$f = fopen("file.txt", "r");$line = fgets($f);while ($line !== FALSE) { var_export($line); $line = fgets($f);}fclose($f);
for line in open("file.txt"): print repr(line)
## またはwith open("file.txt") as f: for line in f: print repr(line)
152
ファイルが存在するかどうかPHP Python
file_exists("file_or_dir");is_file("file.txt");is_dir("/tmp");
import osos.path.exists("file_or_dir")os.path.isfile("file.txt")os.path.isdir("/tmp")
153
ファイル操作PHP Python
rename("old", "new")unlink("file")mkdir("dir")rmdir("dir")
import osos.rename("old", "new")os.unlink("file")os.mkdir("dir")os.rmdir("dir")
154
ファイル名操作PHP Python
$s = "path/to/file";basename($s);dirname($s);
glob('*.txt');
import oss = 'path/to/file'os.path.basename(s)os.path.dirname(s)
import globglob.glob('*.txt')
155
例外処理
156
基本構文Python
try: raise Exception("message")except TypeError, ex: print exexcept (KeyError, NameError), ex: print exfinally: pass タプルを使って複数のエ
ラークラス名を指定可能
157
raisePython
raise NameError('Haruhi: no such student.') # 例外オブジェクトraise NameError, 'Haruhi: no such student.' # クラスと引数raise # 例外を再送
try: import sosexcept ImportError: logging.info('sos: module not found.') raise # 例外をログに記録してから再送
158
else節Python
try: f = open('file.txt')except Exception, ex: print str(ex)else: print f.read()finally: if f: f.close()
•例外が発生しなかったときだけ else 節が実行される
159
例外オブジェクトPython
try: raise Exception('mesg', 123, True)except Exception, ex: print ex.message print ex.args #=> ('mesg', 123, True) arg1, arg2, arg3 = ex # 多重代入が可能 print [arg1, arg2, arg3] #=> ['mesg', 123, True]
160
例外クラスPython
class HttpError(Exception): pass
class Http404NotFound(HttpError): status = '404 Not Found' def __init__(self, url): self.url = url self.message = 'Page Not Found' def __str__(self): return self.message
• Exceptionクラスを継承する•種類ごとに基底クラスを定義するとよい
• __str__()を適切にオーバーライドするとよい (str(ex) でメッセージが表示されるようになる)
161
主な例外クラス (1)Python
# SynstaxError … 文法が間違っている、またはコードに日本語が# 含まれているのにマジックコメントがないTrue && True #=> SyntaxError: invalid syntax
# TypeError … データや引数の型または数が間違っているlist1 = ['Haruhi','Mikuru','Yuki']list1["3"] #=> TypeError: list indices must be integerslist1.append('Kyon', 'Itsuki') #=> TypeError: append() takes exactly # one argument (2 given)
162
主な例外クラス (2)Python
# ValueError … 型は正しいが値として間違っているf = open('members.txt')f.close()f.read() #=> ValueError: I/O operation on closed file
# UnicodeEncodeError … ユニコード関連のエラーprint u'ハルヒ'.encode('utf-8')print u'ハルヒ' #=> UnicodeEncodeError: 'ascii' codec can't # encode characters in position 0-2: ordinal # not in range(128)
163
主な例外クラス (3)Python
# NameError … 変数や関数が存在しないx = haruhi #=> NameError: name 'haruhi' is not defined
# AttributeError … 属性やメソッドが存在しない、# または変数がNoneであるclass Kyon(object): passKyon().megane #=> AttributeError: 'Kyon' object has # no attribute 'megane'None.megane #=> AttributeError: 'NoneType' object has # no attribute 'megane'
164
主な例外クラス (4)Python
# KeyError … 辞書のキーが存在しない{'a':1}['b'] #=> KeyError: 'b'
# IndexError … リストやタプルで添字が範囲外list1 = ['Haruhi','Mikuru','Yuki']list1[3] #=> IndexError: list index out of range
# IOError … ファイルが存在しない、アクセス権限がない、等open('haruhi.txt') #=> IOError: [Errno 2] No such file # or directory: 'haruhi.txt'
165
主な例外クラス (5)Python
# ImportError … 存在しないモジュールをimportしようとしているimport sos #=> ImportError: No module named sos
166
組み込み例外クラスの一覧Python
## 組み込みの例外クラスをすべて表示するfor name, val in vars(__builtins__).iteritems(): if isinstance(val, type) and issubclass(val, Exception): print name # 名前だけ表示 print "%s: %s" % (name, val.__doc__) # ドキュメントも表示
167
正規表現
【関連ドキュメント】
• ライブラリリファレンス: re - 正規表現http://www.python.jp/doc/release/lib/module-re.html
• チュートリアル: 10.5 文字列のパターンマッチングhttp://www.python.jp/doc/release/tut/node12.html#SECTION0012500000000000000000
168
パターンマッチPHP
Python
$s = '<img src="logo.gif">';if (preg_match('/src="(.*?)"/', $s, $m)) echo $m[0], " ", $m[1]; #=> src="logo.gif" logo.gif
import res = '<img src="logo.gif">'m = re.search(r'src="(.*?)"', s)if m: print m.group(0), m.group(1) #=> src="logo.gif" logo.gif
• re.match()は先頭にマッチ• re.search()は途中にもマッチ
169
オプション指定PHP
Python
$s = '<h1>Title</h1>';if (preg_match('/^<h1>(.*?)<\/h1>$/msi', $s, $m)) echo $m[1];
import res = '<h1>Title</h1>'m = re.search(r'^<h1>(.*?)</h1>$', s, re.M|re.S|re.I)if m: m.group(1)
• re.search()の第3引数にオプション指定
170
置換PHP
Python
$s = '<img src="logo.gif">';echo preg_replace('/(\w+\.gif)/', 'img/\1', $s); #=> <img src="img/logo.gif">
import res = '<img src="logo.gif">'print re.sub(r'(\w+\.gif)', r'img/\1', s) #=> <img src="img/logo.gif">
• re.sub() の第4引数に置換回数を指定できる (例: 1 なら最初の1回だけ置換)
171
コールバックつき置換PHP
Python
$ESC = array('<'=>'<', '>'=>'>', '&'=>'&');function f($m) { global $ESC; return $ESC[$m[0]]; }echo preg_replace_callback('/[<>&]/', 'f', '<A&B>');
import reESC = {'<':'<', '>':'>', '&':'&'}f = lambda m: ESC[m.group(0)]print re.sub(r'[<>&]', f, '<A&B>') #=> <A&B>
•コールバック関数の実行結果で置換される
172
繰り返しマッチPHP
Python
$s = file_get_contents("index.html");preg_match_all('/href="(.*?)"/', $s, $arr);foreach ($arr[0] as $url) echo $url, "\n";
import res = open("index.html").read()for m in re.finditer(r'href="(.*?)"', s): print m.group(1) • re.findall()はリストを返す
• re.finditer()はイテレータ(後述)を返す
173
分割PHP
Python
$s = '/public/img/logo.gif';$arr = preg_split('/\//', $s);var_export($arr); #=> array(0=>'', 1=>'public', 2=>'img', 3=>'logo.gif')
import res = '/public/img/logo.gif'list1 = re.split(r'/', s)print list1 #=> ['', 'public', 'img', 'logo.gif']
• re.split()の第3引数に最大分割数を指定できる
174
コンパイルPHP
Python
## 該当機能なし
import res = '<h1>Title</h1>'pattern = re.compile(r'^<h1>(.*?)</h1>$', re.M|re.S|re.I)m = pattern.search(s)if m: m.group(1) •正規表現を事前にコンパイル可能
•実行効率は多少よくなる
175
メソッド一覧reパッケージ patternオブジェクト
re.match(rexp, str)re.search(rexp, str)re.sub(rexp, repl, str, n=0)re.subn(rexp, repl, str, n=0)re.split(rexp, str, n=0)re.findall(rexp, str)re.finditer(rexp, str)re.compile(rexp, repl, str)re.purge(rexp, repl, str)re.escape(rexp, repl, str)
pattern.match(str)pattern.search(str)pattern.sub(repl, str, n=0)pattern.subn(repl, str, n=0)pattern.split(str, n=0)pattern.findall(str)pattern.finditer(str)---
pattern = re.compile(rexp)
176
高階関数、クロージャ
【関連ドキュメント】
• チュートリアル: 4.6 関数を定義するhttp://www.python.jp/doc/release/tut/node6.html#SECTION006600000000000000000
• 言語仕様リファレンス: 4.1 名前づけと束縛 (naming and binding)http://www.python.jp/doc/release/ref/naming.html
• 言語仕様リファレンス: 7.6 関数定義http://www.python.jp/doc/release/ref/function.html
177
高階関数とは?✤ 関数をデータとして扱う関数
✤ 関数を引数とする関数✤ 関数を戻り値とする関数
Python
def f(n): return n*n # 関数の定義f = lambda n: n*n # 関数の作成
•「関数を定義する」=「関数オブジェクトを作成 (して変数に代入) する」
•関数オブジェクトをデータとして扱える
178
よくある光景Python
def map_square(items): L = [] for x in items: L.append(x * x) return L
nums = [1, 2, 3]print map_square(nums) #=> [1, 4, 9]
•一部の処理が違うだけで、あとは一緒の関数
def map_label(items): L = [] for x in items: L.append("(%s)" % x) return L
nums = [1, 2, 3]print map_label(nums) #=> ['(1)', '(2)', '(3)']
179
関数を引数にとる関数: mapPython
def map(func, items): L = [] for x in items: L.append(func(x)) return L
•違う処理を関数で与える• map() は組み込み関数として提供済
nums = [1, 2, 3]f = lambda n: n*nprint map(f, nums)
f = lambda n: '(%s)' % nprint map(f, nums)
180
関数を引数にとる関数: filterPython
def filter(func, items): L = [] for n in items: if func(n): L.append(n) return L
•条件を満たす要素だけを集める関数
• filter() は組み込み関数として提供済
nums = [1, 7, 3, 2, 0, 5, 0, 8]print filter(lambda n: n % 2, nums) #=> [1, 7, 3, 5]
print filter(lambda n: n > 5, nums) #=> [7, 8]
181
関数を引数にとる関数: maxPython
def max_by(func, items): is_first = True for x in items: v = func(x) if is_first: max, item = v, x! is_first = False elif max < v: max, item = v, x return item
•評価関数が最大になる要素を返す•組み込み関数 max(items, key=func) が提供済
SOS = [('Haruhi', 'C'), ('Mikuru', 'E'), ('Yuki', 'A'), ]f = lambda x: x[1]print max_by(f, SOS) #=> ('Mikuru', 'E')
182
関数を引数にとる関数: reducePython
def reduce(func, items, init): accum = init for x in items: accum = func(accum, x) return accum
•累積値 (accum) と要素 (x) を使って何らかの処理を行う関数
•組み込み関数として提供済
nums = xrange(1, 10+1)func = lambda a, x: a+xprint reduce(func, nums, 0) #=> 55
183
関数を返す関数Python
odd, even = "#FCC", "#CCF"def oddeven(): def func(n): if n % 2 == 1: return odd else: return even return func
f = oddeven()print f(1) #=> #FCCprint f(2) #=> #CCFprint f(3) #=> #FCC
関数内部で作成した関数を返す
普通に定義した関数と同様に利用可能
•「関数を定義する」=「関数オブジェクトを作成 (して変数に代入) する」
184
外側のローカル変数を参照Python
def oddeven(odd, even): def func(n): if n % 2 == 1: return odd else: return even return func
f1 = oddeven("red", "blue")print f1(1) #=> redprint f1(2) #=> blueprint f1(3) #=> red
f2 = oddeven("#FCC", "#CCF")print f2(1) #=> #FCCprint f2(2) #=> #CCFprint f2(3) #=> #FCC•グローバル変数を使わない
ので、挙動の異なる関数を多数作成できる
185
クロージャ✤ 関数+外側のローカル変数
✤ 内側の関数オブジェクトが生存する間は、それが参照している、外側のローカル変数も生存する(すぐには消えない)。
Python
def oddeven(odd, even): def func(n): if n % 2 == 1: return odd else: return even return func
f1 = oddeven('#FCC', '#CCF')print f1(1), f1(2), f1(3)f2 = oddeven('red, 'blue')print f2(1), f2(2), f2(3)
•内側の関数が存命中なので、変数oddとevenも存命中
186
クロージャではない例Python
def oddeven(odd, even): def func(n): if n % 2 == 1: return '#FCC' else: return '#CCF' return func
odd, even = '#FCC', '#CCF' def oddeven(): def func(n): if n % 2 == 1: return odd else: return even return func
•どちらも、外側のローカル変数を参照していないので、クロージャではない
187
変数スコープPython
def outer(): # グローバル変数 a = b = c = 0 # outer()のローカル変数 d = [] # 同上 def inner(): # 同上 print a # 同上 b = 1 # inner()のローカル変数 nonlocal c # Python 3.0以降で利用可能 c = 1 # outer()のローカル変数(Python 3.0以降) d[0] = 1 # outer()のローカル変数 return inner # 同上
188
引数の部分適用✤ N個の引数を持つ関数にM個の引数を与えることで、
(N-M)個の引数を持つ関数を新たに作成することPython
def map_square(items): func = lambda x: x*x return map(func, items)
## 変形func = lambda x: x*xdef _map(items): return map(func, items)map_square = _map
## さらに変形def map_builder(func): def _map(items): return map(func, items) return _mapmap_square = \ map_builder(lambda x: x*x)map_increase = \ map_builder(lambda x: x+1)
部分適用を行う関数
189
デコレータ
【関連ドキュメント】
• 言語仕様リファレンス: 7.6 関数定義http://www.python.jp/doc/2.5/ref/function.html
190
デコレータ✤ 関数を修飾するための機能
✤ 実体は、関数を受け取り関数を返すような関数
Python
class Foo(object): @classmethod def hello(cls): print "Hello World!" ## これは次と同じ hello = classmethod(hello)
class Foo(object): @foo(123, "bar") def hello(cls): print "Hello World!" ## これは次と同じ func = foo(123, "bar") hello = func(hello)
引数指定も可能
191
サンプル: TemplateMethod(1)Python
def with_dummy(func): def newfunc(self): open('A.txt', 'w') \ .write('AAA') # setup try: func(self) # do test finally: os.unlink('A.txt') # teardown return newfunc
## 使用例@with_dummydef test_1(self): # ... A.txt を使ったテスト...
@with_dummydef test_2(self): # ... A.txt を使ったテスト...
もとの関数を呼び出すような新しい関数を生成して返す
デコレータは、関数を受け取り、関数を返すような関数
192
サンプル: TemplateMethod(2)Python
def with_dummy(fname, data): def deco(func): def newfunc(self): open(fname, 'w') \! .write(data) try: func(self) finally: os.unlink(fname) return newfunc return deco
## 使用例@with_dummy('x.txt', 'XXX')def test_1(self): # ... y.txt を使ったテスト...
@with_dummy('y.txt', 'YYY')def test_2(self): # ... y.txt を使ったテスト...
生成したデコレータを返す
デコレータを生成する関数
193
サンプル: メモ化デコレータ(1)Python
def memoize(f): memo = {} def g(n): if n not in memo: memo[n] = f(n) return memo[n] return g
## 使用例@memoizedef fib(n): if n <= 2: return 1 else: return fib(n-1)+fib(n-2)
print fib(50) # 爆速!
デコレータは、関数を1つ受け取り、かつ関数を返すような関数
f()の計算結果を保存し、再利用する
194
サンプル: メモ化デコレータ(2)Python
## 任意個の引数をとれるよう拡張def memoize(f): memo = {} def g(*args): if args not in memo: memo[args] = f(*args) return memo[args] return g
## 使用例@memoizedef tak(x, y, z): if x <= y: return y else: return tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y))
print tak(13, 5, 0) #=>13
任意個の引数を受け取り、…
それらをまるごとf()に渡す
引数が複数個ある関数にも適用可能
argsはタプルなので辞書のキーとして利用可能
195
サンプル:任意の引数へ対応Python
## 任意の関数の戻り値を## 2倍するデコレータdef cheat(f): def g(*args, **kwargs): v = f(*args, **kwargs) return 2*v return g
## 使用例@cheatdef add(x,y): return x+yprint add(3, y=5) #=> 16
受け取ったすべての引数を、キーワード引数も含めて別の関数にそのまま渡す
引数のどんな渡し方でも大丈夫
196
サンプル:デコレータ生成関数Python
def cheat(n): def _cheat(f): def g(*args, **kwargs): v = f(*args, **kwargs) return n * v return g return _cheat
## 使用例@cheat(3)def add(x,y): return x+yprint add(3, 5) #=> 24
デコレータを生成する関数
デコレータを返す
デコレータ
197
イテレータ
【関連ドキュメント】
• チュートリアル: 9.8 イテレータ (iterator)http://www.python.jp/doc/release/tut/node11.html#SECTION0011800000000000000000
• ライブラリリファレンス: 3.5 イテレータ型http://www.python.jp/doc/release/lib/typeiter.html
198
イテレータとは?✤ 「繰り返し」という概念を抽象化
✤ 「次の値を取得する」と「次の値がなければ終了する」✤ 違うデータ構造に対し同一の方法で繰り返しが可能になる
Python
list1 = [10, 20, 30]it = list1.__iter__()print it.next() #=> 10print it.next() #=> 20print it.next() #=> 30print it.next() #=> StopIteration
イテレータを生成
終了時に例外を発生
next()で次の値を取得199
イテレータとfor文Python
## これは次と (だいたい) 同じit = [10, 20, 30].__iter__()try: while True: item = it.next() print itemexcept StopIteration: pass
• for文は内部でイテレータを生成し実行している
for item in [10, 20, 30]: print item
200
イテレータとfor文 (cont)Python
## これは次と (だいたい) 同じit = open('file.txt').__iter__()try: while True: line = it.next() print line,except StopIteration: pass
for line in open('file.txt'): print line,
201
サンプル: ListItemsPython
class ListItems(object): def __init__(self, list1): self.list = list1 self.i = -1 def __iter__(self): return self def next(self): self.i += 1 if self.i >= len(self.list): raise StopIteration() item = self.list[self.i] return "<li>%s</li>" % item
## 使用例list1 = ['foo', 'bar', 'baz']for s in ListItems(list1): print s
## 実行結果<li>foo</li><li>bar</li><li>baz</li>
202
ジェネレータ
【関連ドキュメント】
• チュートリアル: 9.9 ジェネレータ (generator)http://www.python.jp/doc/release/tut/node11.html#SECTION0011900000000000000000
• 言語仕様リファレンス: 6.8 yield 文http://www.python.jp/doc/release/ref/yield.html
203
通常の関数Python
## 通常の関数def f1(): x = 10 return x x += 1 return x x += 1 return x
print f1() #=> 10print f1() #=> 10print f1() #=> 10print f1() #=> 10
•呼び出すごとに最初から実行される
•ローカル変数の値は保存されない
204
ジェネレータPython
## ジェネレータ関数def ex1_gen(): x = 10 yield x x += 1 yield x x += 1 yield x
## ジェネレータオブジェクトを生成g = ex1_gen()print g.next() #=> 10print g.next() #=> 11print g.next() #=> 12print g.next() #=> StopIteration
•再開可能な関数 (resumable function)• yield で実行を一次中断し、.next() で再開(RPGのセーブと類似)
•最後に例外StopIterationが発生
205
サンプル:フィボナッチ数列Python
def fib(): x, y = 1, 1 while True: yield x x, y = y, x+y
g = fib()print g.next() #=> 1print g.next() #=> 1print g.next() #=> 2print g.next() #=> 3print g.next() #=> 5print g.next() #=> 8print g.next() #=> 13print g.next() #=> 21
ジェネレータ関数 ジェネレータオブジェクト
再帰を使わないので爆速
206
サンプル:cycle()Python
def cycle(*args): i = 0 n = len(args) while True: yield args[i] i += 1 if i == n: i = 0
g = cycle("odd", "even")print g.next() #=> oddprint g.next() #=> evenprint g.next() #=> odd
f = cycle("odd", "even").nextprint f() #=> oddprint f() #=> evenprint f() #=> odd
ジェネレータ関数 ジェネレータオブジェクト
207
ジェネレータとイテレータPython
g = ex1_gen() print repr(g) #=> <generator at 0x13c0200>print repr(g.__iter__()) #=> <generator at 0x13c0200>
• .__iter__() は自分自身を返す• .__iter__() と .next() があるので
for 文で使える
for val in ex1_gen(): print val
## 次とほぼ同じg = ex1_gen().__iter__()try: while True: print g.next()except StopIteration: pass
208
利点:長いリストを作らずに済むPython
range(1, 5) #=> [1,2,3,4]xrange(1,5) #=> xrange
for i in range(1, 1000001): print ifor i in xrange(1, 1000001): print i
• range()は長いリストを生成する(=メモリを大量に消費)
• xrange()はxrangeオブジェクトをひとつ作成するだけ(=メモリ消費量が少ない)
209
利点:「無限」を扱えるPython
## .next() が呼び出される## 限りフィボナッチ数列## を無限に計算し続けるdef fib_gen(): x, y = 0, 1 while True: x, y = y, x+y yield x
## フィボナッチ数列を## 無限に出力し続けるg = fib_gen()while True: print g.next()
210
利点: '処理' と '条件' を分離Python
• generatorなしだと、「計算」や「処理」と、ループの終了判定とが混在=終了条件が異なれば、「計算」や「処理」をもう一度書かなければいけない
## 1000個までのfib数列x, y = 0, 1i = 0while i < 1000: i += 1 x, y = y, x+y print x
## 1000 未満までのfib数列x, y = 0, 1x, y = y, x+ywhile x < 1000: print x x, y = y, x+y
211
利点: '処理' と '条件' を分離Python
## .next() が呼び出される## 限りフィボナッチ数列## を無限に計算し続けるdef fib_gen(): x, y = 0, 1 while True: x, y = y, x+y yield x
•「無限」が扱える=終了条件を指定しなくてよい (別途指定できる)=ループの「処理」と「終了条件」とを分離できる
## 1000個g = fib_gen()i = 0while i < 1000: i += 1 n = g.next() print n
## 1000 未満g = fib_gen()n = g.next()while n < 1000: print n n = g.next()
212
ジェネレータ式Python
g = ( (i, i*i) for i in xrange(1, 5) )print g #=> <generator object>print g.next() #=> (1, 1)print g.next() #=> (2, 4)print g.next() #=> (3, 9)print g.next() #=> (4, 16)print g.next() #=> StopIteration
•丸カッコの中に内包表記 (list complehension) を書くと、それだけでジェネレータになる
213
ジェネレータ式 (cont)Python
names = ['Haruhi', 'Mikuru', 'Yuki']tuples = [ (s, len(s)) for s in names ]print tuples #=> [('Haruhi', 6), ('Mikuru', 6), ('Yuki', 4)]d1 = dict(tuples)print d1 #=> {'Haruhi': 6, 'Mikuru': 6, 'Yuki': 4 }d2 = dict( (s, len(s)) for s in names )print d2 #=> {'Haruhi': 6, 'Mikuru': 6, 'Yuki': 4 }
•引数のカッコの中にジェネレータ式が書ける•リストを引数にとる関数は、ジェネレータも受け付けることが多い
214
.next()と.send()
## ジェネレータ yield 123
yield 456
## メインプログラムval = g. next() # val == 123
val = g.next() # val == 456
val = g.next() # StopIterationStopIteration
•ジェネレータからメインへは値を渡せる (yield の引数)•その逆は?
215
.next()と.send() (cont)
## ジェネレータ ret = yield 123
ret = yield 456
## メインプログラムval = g. next() # or .send(None) # val == 123
val = g.send('aaa') # val == 456
val = g.send('bbb') # StopIteration
# ret == 'aaa'
# ret == 'bbb'
StopIteration
• .send() を使う (.send()の引数がyieldの戻り値)• .send(None) は .next() と同じ
216
ジェネレータ: サンプルPython
# -*- coding: utf-8 -*-def yome_gen(): ans = yield '(a)元気な子 (b)おとなしい子' if ans == 'a': ans = yield '(a)ツンデレ (b)笑い上戸' yome = ans == 'a' and 'ハルヒ' or '鶴屋さん' elif ans == 'b': ans = yield '(a)巨乳 (b)貧乳' yome = ans == 'a' and 'みくる' or '長門' raise StopIteration(yome)
• yield で値 (=質問文) を返しながら、同時に別の値 (=ユーザ回答) を受け取っている
217
ジェネレータ: サンプル (cont)Python
g = yome_gen()ans = Nonetry: while True: question = g.send(ans) print question, ' >>', ans = raw_input()except StopIteration, ex: yome = ex.args[0] print 'おすすめは', yome
## 実行例
(a)元気な子 (b)おとなしい子 >> a
(a)ツンデレ (b)笑い上戸 >> bおすすめは 鶴屋さん
g.send(None) は g.next() と同じ
• send() で値 (=ユーザ回答) を渡しながら、かつ戻り値 (=質問文) を受け取っている
218