はじめてのPython
2019 T.Takeda
知っておくべきいくつかのこと
- インタプリタ言語
- 動的型付け言語、強い型付け
- ガベージコレクションを持つ
- Python2と3は別物
- Pythonのパフォーマンス
- Python/pandasの注意点
インタプリタ言語
実行時に解釈され、順に実行される
- コンパイルしないため、実行速度が遅い
- 動かすまで何が起こるかわからない怖さ
強い動的型付け言語
実行時に型が決定される言語
- 動的で危ないことを認識する
- いつの間にか数値が文字列になったりはしない
- プログラミング初心者には使いやすいが品質担保が難しいことを理解する
💡型アノテーションは単なる注釈で機能的な意味は薄い
ガベージコレクション(GC)
PythonはGCを備えており、メモリ制御を明示的に行う必要がない。
1. いつ確保されて、いつ解放するか理解して利用する必要がある
2. delしたり、関数スコープから出るときにオーバーヘッドがあることを意識する
3. 知らないと見えないところで遅くなる
- 解放されるタイミングは任意だが、参照が残るとメモリリークする
💡GC呼び出しを手動でやるときは何かおかしいので思いとどまる
オフサイドルール
- インデントが構文規則であり、揃える必要がある
- インデントがずれてもオフサイドルールが合っているとエラーはしないので注意
💡リファクタリング時にずれることがあるので特に注意が必要
Python2/3
- Python2はUnicodeという病により死んだ
- Python3のことを知ろう
💡新しいものは全部Python3.xで始める
Cython
- Pythonは動作パフォーマンスが悪い言語
- パフォーマンスが必要な箇所では、C/C++/Fortranで動いている
Pythonの流行
研究/学術目的で使いやすかった
- 数値計算ライブラリnumpyを筆頭にscipy、pandas、matplotlibなどの存在
💡機械学習が後押しし、研究から実用に転じた印象
Haskellに習う
Python2はHaskellを参考にしたにも関わらず、関数型のパラダイムをいち早く取り込んだだけで終わった
Pythonパフォーマンス改善
for文より、リスト内包表記
これで歩行者が競歩くらい速くなる
res = []
for item in items:
res.append({
'piyo': item
})
res = [{'piyo': item} for item in items]
💡set, dictなどジェネレータを呼び出すものも同様
💡list()ではなく、内包表記を推奨
Pythonパフォーマンス改善
繰り返しの参照は変数に代入
これで競歩が自転車くらい速くなる
for item in items:
self.validation(item)
validation = self.validation
for item in items:
validation(item)
💡参照、関数呼び出しのオーバーヘッドはかなり重い
💡やり過ぎると可読性を下げる
Pythonパフォーマンス改善
定数定義はループの外に
これで自転車が原付バイクくらい速くなる
for item in items:
init_val = {
'name': ini.get('section', 'name')
}
name = ini.get('section', 'name')
for item in items:
init_val = {
'name': name
}
💡最適化されずに毎回同じ計算が走ることを回避
Pythonパフォーマンス改善
インスタンス作成はループの外に
これで原付バイクが大型バイクくらい速くなる
event = { ... }
for item in items:
data = Data(event)
data.select(item)
...
event = { ... }
data = Data(event)
for item in items:
data.select(item)
...
💡オブジェクトの生成コストは相応に大きいため、スコープに閉じて再生成させない
Pythonの注意点
raiseとraise eは別物
try:
ret = sugoi_kinou()
except Exception as e:
raise e
try:
ret = sugoi_kinou()
except Exception:
raise
💡raise eは後続に渡すexception内容を自身以降に限定する
Pythonの注意点
意図もなくマングリングしない
def __process():
yeah = party(people)
def _process():
yeah = party(people)
💡アンダースコア一つはプライベートに使う関数/変数の意味
Pythonの注意点
参照渡しと値渡しはある
- 型により挙動が変わる
- 暗黙的に受け取り先で値を書き換えてはいけない(副作用)
def func(args):
...
n = 22
func(n) # 値渡し
l = [0, 1, 2]
func(l) # 参照渡し
💡プリミティブ型は値渡し、リストや辞書は参照渡し
pandasの注意点
DataFrameの要素をループしない
これで亀がスペースシャトルくらいになる
for index, row in df.iterrows():
row['sum'] = row['val1'] + row['val2']
df['sum'] = df['val1'] + df['val2']
💡pandasに限らず、関数型パラダイムを持つ手続き型言語でよく見られる
💡iterrows/ilocを使う場合は、本当にDataFrameである必要があるか考える
pandasの注意点
同様にSeriesをループしていることがある
💡tolist()するなら最初からリストでやった方がよい場合もある
💡DataFrameとListの行き来もオーバーヘッドが大きい
pandasの注意点
filterするなら先にやる
df.apply(func).filter(cond)
df.filter(cond).apply(func)
💡pandasに限らず手続き型では無駄な処理が減るので、処理したいデータに先に絞る
Pythonの注意点
バックスラッシュで改行、括弧内で改行
res = df.filter() \
.apply()
res = (df.filter()
.apply())
💡もちろん、好みもある
💡Pythonでは、PEP8を読むことが大事
昨今のPythonの使いどころ
Pythonの善し悪しを理解して使おう
- クライアントサイドPython
- DeepLearning/MachineLearning
- Jupyter
- サーバーサイドPython
- Serverless(AWS Lambdaなど)
- Django
💡よいPythonライフを!