Pythonアクセサリー類の使用——bound/unbound method
3686 ワード
引用する
デコレーションクラスの方法を学習したところ、デコレーションクラスが__しかない場合call __メソッドは通常の関数(function)のみを装飾し,インスタンスメソッド(instance method)を装飾することはできず,pythonの関数実装と関係があることが分かった.本論文では,これについて議論を展開し,完全な装飾器クラス実装方法を提示する.
問題の発見
クラスのインスタンスメソッドを呼び出すと、インスタンスはメソッドの最初のパラメータselfとして使用されることを知っています.なお、以下の例では、実例の方法fooがデコレーション類Decoratorによりデコレーション後、Decorated()とする.foo('hello,world')の最初のselfはDecoratedインスタンスではなく、私たちが伝えた「hello,world」であり、明らかにこれは私たちの予想に合わない.実際にはpythonの関数呼び出しに関係し、bound method(インスタンス呼び出しによるメソッド)はインスタンス自体をメソッドの最初のパラメータとして自動的に入力しますが、functionおよびunbound method(クラス直接呼び出しのメソッド)はインスタンスを自動的に注入しません.デコレーションで装飾すると、Decoratorに入力されたfuncはboundプロパティを失い、自動的にインスタンスに注入されません.
function、bound methodとunbound methodの違い
前節ではbound methodとunboud methodについて述べたが,この節ではこれらの概念を具体的に説明する.
fooはfunctionタイプでクラスの
Cls.fooは
メソッドの変更
解析により,基本的な原因は,装飾されたfooがDecoratorインスタンスのメンバー変数として機能し,そのタイプはfunctionでありbound属性を失い,instanceインスタンスを関数の最初のパラメータに自動的に注入できないことにあることが分かった.これを解決するために、クラスまたはインスタンスによってアクセスするときにtypesを通過する記述器としてDecoratorを実装することができる.MethodTypeはDecoratorインスタンスをmethodにパッケージします.
参考文献
The Inside Story on New-Style Classes python - Instancemethod or function? - Stack Overflow Chris’s Wiki::blog/python/HowFunctionsToMethods Descriptor HowTo Guide — Python 2.7.15 documentation python - How can I decorate an instance method with a decorator class? - Stack Overflow Glossary — Python 2.7.15 documentation
デコレーションクラスの方法を学習したところ、デコレーションクラスが__しかない場合call __メソッドは通常の関数(function)のみを装飾し,インスタンスメソッド(instance method)を装飾することはできず,pythonの関数実装と関係があることが分かった.本論文では,これについて議論を展開し,完全な装飾器クラス実装方法を提示する.
問題の発見
クラスのインスタンスメソッドを呼び出すと、インスタンスはメソッドの最初のパラメータselfとして使用されることを知っています.なお、以下の例では、実例の方法fooがデコレーション類Decoratorによりデコレーション後、Decorated()とする.foo('hello,world')の最初のselfはDecoratedインスタンスではなく、私たちが伝えた「hello,world」であり、明らかにこれは私たちの予想に合わない.実際にはpythonの関数呼び出しに関係し、bound method(インスタンス呼び出しによるメソッド)はインスタンス自体をメソッドの最初のパラメータとして自動的に入力しますが、functionおよびunbound method(クラス直接呼び出しのメソッド)はインスタンスを自動的に注入しません.デコレーションで装飾すると、Decoratorに入力されたfuncはboundプロパティを失い、自動的にインスタンスに注入されません.
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Decorator: self: {}, args: {}, kwargs: {}".format(self, args, kwargs))
return self.func(*args, **kwargs)
class Decorated(object):
@Decorator
def foo(self, *args, **kwargs):
print("Method Decorated: self: {}, args: {}, kwargs: {}".format(self, args, kwargs))
Decorated().foo('hello, world')
# Decorator: self: <__main__.decorator object="" at="">, args: ('hello, world',), kwargs: {}
# Method Decorated: self: hello, world, args: (), kwargs: {}
function、bound methodとunbound methodの違い
前節ではbound methodとunboud methodについて述べたが,この節ではこれらの概念を具体的に説明する.
class Cls(object):
def foo(self):
pass
instance = Cls()
print 'foo' in Cls.__dict__ # True
print 'foo' in instance.__dict__ # False
print Cls.foo #
print instance.foo # >
print Cls.__dict__['foo'] #
fooはfunctionタイプでクラスの
__dict__
に存在するが,インスタンスアクセスによりbound methodが得られ,クラスアクセスによりunbound methodが得られることが分かった.これはpythonでは、すべての関数が非資料記述器(no data descriptor)であるためである.クラスまたはインスタンスを介してアクセスすると、__get__
メソッドによってパッケージされ、unbound methodまたはbound methodに戻ります.unboudとboundの違いはmethodのim_です.selfが空かどうか.bound methodはinstanceを自動的に最初のパラメータとして使用しますが、unbound methodはパラメータに対して何も処理しません.前のセクションの例では、fooはDecoratorのメンバー変数として、typeはfunctionであるため、インスタンスは自動的に注入されません.Cls.fooは
Cls.__dict __[‘foo’].__get__(None, Cls)
に翻訳され、unbound method(im_self is None)instanceを返します.fooはtype(instance).__dic __[‘foo’].__get__(instance, type(instance))
に翻訳され、bound method(im_self==instance)instance.foo(args, kwargs)
がCls.foo(instance, args, kwargs)
に等しいことを返します.メソッドの変更
解析により,基本的な原因は,装飾されたfooがDecoratorインスタンスのメンバー変数として機能し,そのタイプはfunctionでありbound属性を失い,instanceインスタンスを関数の最初のパラメータに自動的に注入できないことにあることが分かった.これを解決するために、クラスまたはインスタンスによってアクセスするときにtypesを通過する記述器としてDecoratorを実装することができる.MethodTypeはDecoratorインスタンスをmethodにパッケージします.
class Decorator(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return types.MethodType(self, instance, owner)
def __call__(self, *args, **kwargs):
print("Decorator: self: {}, args: {}, kwargs: {}".format(self, args, kwargs))
return self.func(*args, **kwargs)
参考文献
The Inside Story on New-Style Classes python - Instancemethod or function? - Stack Overflow Chris’s Wiki::blog/python/HowFunctionsToMethods Descriptor HowTo Guide — Python 2.7.15 documentation python - How can I decorate an instance method with a decorator class? - Stack Overflow Glossary — Python 2.7.15 documentation