まず、名前を正しく取得する必要があります。
>>> def increment(obj):
... obj.count += 1
...
>>> class A(object):
... def __init__(self):
... self.count = 0
...
>>> o = A()
>>> o.__init__
<bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>>
>>> increment
<function increment at 0x00000000027797C8>
したがって、適切な名前は関数とバインドされたメソッドです。これで、バインドされていないメソッドをバインドする方法を探すことができ、おそらく記述子について読むことになるでしょう:
一般に、記述子は「バインディング動作」を持つオブジェクト属性であり、その属性アクセスは記述子プロトコルのメソッドによってオーバーライドされます。それらのメソッドは、、、__get__
および__set__
です
__delete__
。これらのメソッドのいずれかがオブジェクトに対して定義されている場合、それは記述子と呼ばれます。
の異なる呼び出しを使用するだけで、関数をメソッドに簡単に変換できます__get__
>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>
そして、それは魅力のように機能します:
>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2
これらの新しくバインドされたメソッドをオブジェクトに簡単に追加できます。
def increment(obj):
obj.count += 1
def addition(obj, number):
obj.count += number
class A(object):
def __init__(self):
self.count = 0
o = A()
o.inc = increment.__get__(o)
o.add = addition.__get__(o)
print(o.count) # 0
o.inc()
print(o.count) # 1
o.add(5)
print(o.count) # 6
または、関数をバインドされたメソッドに変換する独自の記述子を作成します。
class BoundMethod(object):
def __init__(self, function):
self.function = function
def __get__(self, obj, objtype=None):
print('Getting', obj, objtype)
return self.function.__get__(obj, objtype)
class B(object):
def __init__(self):
self.count = 0
inc = BoundMethod(increment)
add = BoundMethod(addition)
o = B()
print(o.count) # 0
o.inc()
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 1
o.add(5)
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 6
また、これは関数/バインドされたメソッドの原則とうまく一致していることもわかります。
クラス ディクショナリは、メソッドを関数として格納します。クラス定義では、関数を作成するための通常のツールである def と lambda を使用してメソッドが記述されます。通常の関数との唯一の違いは、最初の引数がオブジェクト インスタンス用に予約されていることです。Python の慣例により、インスタンス参照は self と呼ばれますが、this または他の変数名と呼ばれることもあります。
メソッド呼び出しをサポートするために、関数には、__get__()
属性アクセス中にメソッドをバインドするためのメソッドが含まれています。これは、すべての関数が、オブジェクトまたはクラスのどちらから呼び出されたかに応じて、バインドされたメソッドまたはバインドされていないメソッドを返す非データ記述子であることを意味します。
そして、関数はインスタンスの初期化中にバインドされたメソッドになります:
>>> B.add
# Getting None <class '__main__.B'>
<function addition at 0x00000000025859C8>
>>> o.add
# Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'>
<bound method B.addition of <__main__.B object at 0x00000000030B1128>>