同じラッパーで Python のいくつかのクラス メソッドをラップしたいと思います。
概念的には、最も単純なシナリオでは次のようになります。
x = 0 # some arbitrary context
class Base(object):
def a(self):
print "a x: %s" % x
def b(self):
print "b x: %s" % x
class MixinWithX(Base):
"""Wrap"""
def a(self):
global x
x = 1
super(MixinWithX, self).a()
x = 0
def b(self):
global x
x = 1
super(MixinWithX, self).a()
x = 0
もちろん、a
とよりも多くのメソッドがある場合b
、これはめちゃくちゃになります。もっとシンプルなものが必要なようです。明らかにx
デコレータで変更できますが、それでも長いゴミのリストができてしまい、上記の代わりに次のようになります。
from functools import wraps
def withx(f):
@wraps(f) # good practice
def wrapped(*args, **kwargs):
global x
x = 1
f(*args, **kwargs)
x = 0
return wrapped
class MixinWithX(Base):
"""Wrap"""
@withx
def a(self):
super(MixinWithX, self).a()
@withx
def b(self):
super(MixinWithX, self).b()
ミックスインで使おうと思っ__getattr__
たのですが、もちろんa
やなどのメソッドb
は定義済みなので、これが呼び出されることはありません。
使用することも考えまし__getattribute__
たが、呼び出しをラップするのではなく、属性を返します。__getattribute__
クロージャーを返すことができると思いますが(以下の例)、それがどの程度健全な設計であるかはわかりません。次に例を示します。
class MixinWithX(Base):
# a list of the methods of our parent class (Base) that are wrapped
wrapped = ['a', 'b']
# application of the wrapper around the methods specified
def __getattribute__(self, name):
original = object.__getattribute__(self, name)
if name in wrapped:
def wrapped(self, *args, **kwargs):
global x
x = 1 # in this example, a context manager would be handy.
ret = original(*args, **kwargs)
x = 0
return ret
return wrapped
return original
ラップされる親クラスのすべてのメソッドを手動で再作成する必要性を軽減する何かが Python に組み込まれている可能性があることに気づきました。または、これを行う適切な方法は でのクロージャかもしれません__getattribute__
。私は考えに感謝します。