開発メモ

Pythonデコレータ

May 20, 2020

 1>>> def outer(x):
 2...     def inner():
 3...         print x
 4...     return inner
 5>>> print1 = outer(1)
 6>>> print2 = outer(2)
 7>>> print1()
 81
 9>>> print2()
102
  • デコレータ=関数を引数にとり,引き換えに新たな関数を返すcallable(*)
    • 与えられた関数に,処理を追加した関数を返す
 1>>> def outer(some_func):
 2...     def inner():
 3...         print "before some_func"
 4...         ret = some_func() #1
 5...         return ret + 1
 6...     return inner
 7>>> def foo():
 8...     return 1
 9>>> decorated = outer(foo) #2
10>>> decorated()
11before some_func
122
  • 座標オブジェクトに対して計算処理を後付したい場合
 1>>> class Coordinate(object):
 2...     def __init__(self, x, y):
 3...         self.x = x
 4...         self.y = y
 5...     def __repr__(self):
 6...         return "Coord: " + str(self.__dict__)
 7>>> def add(a, b):
 8...     return Coordinate(a.x + b.x, a.y + b.y)
 9>>> def sub(a, b):
10...     return Coordinate(a.x - b.x, a.y - b.y)
11>>> one = Coordinate(100, 200)
12>>> two = Coordinate(300, 200)
13>>> add(one, two)
14Coord: {'y': 400, 'x': 400}
15
16>>> def wrapper(func):
17...     def checker(a, b):
18...         if a.x < 0 or a.y < 0:
19...             a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
20...         if b.x < 0 or b.y < 0:
21...             b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
22...         ret = func(a, b)
23...         if ret.x < 0 or ret.y < 0:
24...             ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
25...         return ret
26...     return checker
27>>> add = wrapper(add)
28>>> sub = wrapper(sub)
29>>> sub(one, two)
30Coord: {'y': 0, 'x': 0}
31>>> add(one, three)
32Coord: {'y': 200, 'x': 100}
  • @による糖衣構文
1def add(a, b):
2    return Coordinate(a.x + b.x, a.y + b.y)
3add = wrapper(add)

1@wrapper
2def add(a, b):
3    return Coordinate(a.x + b.x, a.y + b.y)
  • loggerの例
 1>>> def logger(func):
 2...     def inner(*args, **kwargs): #1
 3...         print "Arguments were: %s, %s" % (args, kwargs)
 4...         return func(*args, **kwargs) #2
 5...     return inner
 6>>> @logger
 7... def foo1(x, y=1):
 8...     return x * y
 9>>> @logger
10... def foo2():
11...     return 2
12>>> foo1(5, 4)
13Arguments were: (5, 4), {}
1420
15>>> foo1(1)
16Arguments were: (1,), {}
171
18>>> foo2()
19Arguments were: (), {}
202

Tagged: #Python