Decoratorとwith
AOPの考え方と同じ
★Decorator
メソッド式
def deco1(func):
def overwrite():
...
func()
return overwrite
def deco2(func):
import functools
@functools.wraps(func)
def overwrite(*args, **kwargs):
...
func(*args, **kwargs)
return overwrite
def deco3(param):
def wrapper(func):
import functools
@functools.wraps(func)
def overwrite(*args, **kwargs):
...
func(*args, **kwargs)
return overwrite
return wrapper
@deco1
def test1():
...
test1()
print(test1.__name__) # overwrite
@deco2
def test2():
...
test2()
print(test2.__name__) # test2
@deco3('dummy')
def test3():
...
クラス式
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
print("{func} is running".format(func=self.func.__name__))
# 前処理
self._func(*args, **kwargs)
# 後処理
class Foo2(object):
def __init__(self, level='INFO'):
self._level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print("[{level}]:{func} is running" \
.format(level=self._level, func=func.__name__)
# 前処理
self._func(*args, **kwargs)
# 後処理
return wrapper
@Foo
def bar():
...
@Foo2(level='WARN')
def bar():
...
複数の場合に処理順番
@a
@b
@c
def f():
pass
f = a(b(c(f))) と同じ
計測
import time
(async) def measure(func):
import functools
@functools.wraps(func)
def overwrite(*args, **kwargs):
start = int( time.time() * 1000 )
result = (await) func(*args, **kwargs)
end = int( time.time() * 1000 )
print("実行時間:{0}".format(end - start) + "[ms]")
return result
return overwrite
※asyncとawaitをつけると、非同期処理に対応
キャッシュ
from functools import lru_cache
@lru_cache()
# @lru_cache(maxsize=128, typed=False)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
Generic化
from functools import singledispatch
from collections import abc
import numbers
import html
@singledispatch
def htmlize(obj)
content = html.escape(repr(obj))
return f'<pre>{content}</pre>'
@htmlize.register(str)
def _(text):
content = html.escape(text).replace('\n', '<br>\n')
return f'<p>{content}</p>'
@htmlize.register(numbers.Integral)
def _(n):
return f'<pre>{n} (0x{0:x})</pre>'
@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
inner = '</li>\n<li>'.join(htmlize(item) for item in seq)
return '<ul>\n<li>' + inner + '</li>\n</ul>'
Strategy Pattern
promos = []
def promotion(func):
promos.append(func)
return func
@promotion
def strategyA(order):
return ...
@promotion
def strategyB(order):
return ...
def best_promo(order):
return max(promo(order) for promo in promos)
同期ロック
import threading
import functools
def synchronized(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
with self.lock:
return func(self, *args, **kwargs)
return wrapper
class MyWorker(object):
def __init__(self):
self.lock = threading.Lock()
self.idx = 0
@synchronized
def test1(self):
self.idx = self.idx + 1
@synchronized
def test2(self):
self.idx = self.idx + 2
worker = MyWorker()
threading.Thread(target=worker.test1).start()
threading.Thread(target=worker.test2).start()
★with
file = open("filename")
try:
print(file.read())
finally:
file.close()
↓
with open("filename") as file:
print(file.read())
with open('file1', 'w') as f1, open('file2', 'w') as f2:
f1.write('Hello')
f2.write('Hello')
方式1
class CustomOpen(object):
def __init__(self, filename):
self.file = open(filename)
def __enter__(self):
return self.file
def __exit__(self, type, value, traceback):
self.file.close()
with CustomOpen('file') as f:
contents = f.read()
方式2
from contextlib import contextmanager
@contextmanager
def custom_open(filename):
f = open(filename)
try:
yield f
finally:
f.close()
with custom_open('file') as f:
contents = f.read()