Python が大事にしている概念
●
TOOWTDI (There's Only One Way To Do IT)
– やり方はたった 1つでいい
●
Pythonic とは
– 小さなコードパターンに最も効率的なイディオムを使ったコーディングや構文
– Code Like a Pythonista: Idiomatic Python
– The Hitchhiker’s Guide to Python!
●
The Zen of Python (PEP20)
– Beautiful is better than ugly. ( 汚いよりきれい方が良い)
– Explicit is better than implicit. ( 暗黙的よりも明示的な方が良い )
– Although practicality beats purity. ( とはいえ、純粋さよりも実用的であること )
●
The number one thing that Python programmers do is read code.
– コードは書かれるよりも読まれることの方が多い
そんな Python であっても、
コーディングやそのイディオムは同じであっても、
設計の在り方は個々のプログラマーによって違う
人それぞれに設計スタイルが違うの当然で、全体で一貫性があれば良いと思う
Python のイディオムを知ろう
他人のコードを読んでいて
気になるのは Pythonic じゃないコード、
つまりはそのイディオムが共有されてないとき
PEP8 の一節
"A Foolish Consistency is the Hobgoblin of Little Minds"
また、このバランスも難しい
サンプルコード
from functools import lru_cache
@lru_cache(maxsize=None)
def memoize_fib(n):
"""
>>> [memoize_fib(n) for n in range(16)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> memoize_fib.cache_info()
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
"""
if n < 2:
return n
return memoize_fib(n-1) + memoize_fib(n-2)
In [1]: from lru_cache_sample1 import fib, memoize_fib
In [2]: timeit -n 3 [fib(n) for n in range(20)]
3 loops, best of 3: 6.49 ms per loop
In [3]: timeit -n 3 [memoize_fib(n) for n in range(20)]
3 loops, best of 3: 36.2 µs per loop
IPython を使うとパフォーマンスを比較するのが簡単
with 文と contextlib
●
PEP343 The "with" statement
– Lisp でよく使われた with-* マクロから触発?
– コンテキストマネージャーと一緒に使う
●
contextlibを使うと便利
●
グローバル情報の保存/更新
●
リソースのロック/アンロック
●
ファイルのオープン/クローズ
with open('test.txt') as f:
first, *rest, last = f.readlines()
f = open('test.txt')
try:
first, *rest, last = f.readlines()
finally:
f.close()
サンプルコード
from contextlib import
contextmanager
@contextmanager
def my_open(filename):
f = open(filename)
try:
yield f
finally:
f.close()
class MyContextManager:
def __init__(self, filename):
self.filename = filename
self.file = None
def __enter__(self):
self.file = open(self.filename)
return self.file
def __exit__(self, type, value, traceback):
if type is not None:
self.file.close()
コンテキストマネージャの定義
データ構造とアルゴリズム
●
集合型 set の応用例
– 集合演算使うと処理が簡潔になることがある
def has_invalid_fields_loop(fields):
for field in fields:
if field not in ['foo', 'bar']:
return True
return False
def has_invalid_fields_set(fields):
return bool(set(fields) - set(['foo', 'bar']))
ループがなくなった!
上の方が意図は分かりやすい?
下の方がコードが簡潔?
super を使った処理の移譲
●
Python Is Not Java
– ここにある話題じゃないけど、多重継承もその 1 つ
●
Python’s super() considered super!
– super はスーパーだという話
– Python の多重継承は移譲の仕組みを提供
●
MRO(Method Resolution Order): C3線形化アルゴリズム
●
MRO の仕組みを知っていれば後から移譲先を変更できる
●
既存のコードをいじらない → コードが安定する
サンプルコード
>>> class A:
... def f(self):
... print('A')
>>> class B(A):
... def f(self):
... print('B')
... super().f()
>>> class C(B): pass
>>> C.mro()
[<class '__main__.C'>,
<class '__main__.B'>,
<class '__main__.A'>,
<class 'object'>]
>>> C().f()
B
A
>>> class D(A):
... def f(self):
... print('D')
>>> class E(C, D): pass
>>> E.mro()
[<class '__main__.E'>,
<class '__main__.C'>,
<class '__main__.B'>,
<class '__main__.D'>,
<class '__main__.A'>,
<class 'object'>]
>>> E().f()
B
D
B.f メソッドで呼び出す
super が D.f に変更された!
A
B
C
D
E
1
3
2
4
5
object
6