TLDR:インスタンスに適切なバインドされていないメソッドを定義することは不可能です。これは特別な方法にも当てはまります。バインドされたメソッドはファーストクラスのオブジェクトであるため、特定の状況では違いは目立ちません。ただし、特別なメソッドは、必要に応じてPythonによって常に適切なバインドされていないメソッドとして検索されます。
より一般的な属性アクセスを使用する特別なメソッドにいつでも手動でフォールバックできます。属性アクセスは、属性として格納されているバインドされたメソッドと、必要に応じてバインドされているバインドされていないメソッドの両方を対象としています。__repr__
これは、または他のメソッドが属性を使用して出力を定義する方法と似ています。
class A:
def __init__(self, name):
self.name = name
def __repr__(self):
# call attribute to derive __repr__
return self.__representation__()
def __representation__(self):
return f'{self.__class__.__name__}({self.name})'
def __str__(self):
# return attribute to derive __str__
return self.name
アンバウンドメソッドとバウンドメソッド
Pythonのメソッドには、クラスの非バインドメソッドとそのクラスのインスタンスのバインドメソッドの2つの意味があります。
非バインドメソッドは、クラスまたはその基本クラスの1つに対する通常の関数です。クラス定義中に定義することも、後で追加することもできます。
>>> class Foo:
... def bar(self): print('bar on', self)
...
>>> Foo.bar
<function __main__.Foo.bar(self)>
バインドされていないメソッドは、クラスに1回だけ存在します。これは、すべてのインスタンスで同じです。
バインドされたメソッドは、特定のインスタンスにバインドされたバインドされていないメソッドです。__get__
これは通常、関数のメソッドを呼び出すインスタンスを介してメソッドが検索されたことを意味します。
>>> foo = Foo()
>>> # lookup through instance
>>> foo.bar
<bound method Foo.bar of <__main__.Foo object at 0x10c3b6390>>
>>> # explicit descriptor invokation
>>> type(foo).bar.__get__(foo, type(Foo))
<bound method Foo.bar of <__main__.Foo object at 0x10c3b6390>>
Pythonに関する限り、「メソッド」とは通常、必要に応じてそのインスタンスにバインドされるバインドされていないメソッドを意味します。Pythonが特別なメソッドを必要とする場合、バインドされていないメソッドの記述子プロトコルを直接呼び出します。結果として、メソッドはクラスで検索されます。インスタンスの属性は無視されます。
オブジェクトのバインドされたメソッド
バインドされたメソッドは、インスタンスからフェッチされるたびに新しく作成されます。結果は、アイデンティティを持ち、保存して渡すことができ、後で呼び出すことができるファーストクラスのオブジェクトです。
>>> foo.bar is foo.bar # binding happens on every lookup
False
>>> foo_bar = foo.bar # bound methods can be stored
>>> foo_bar() # stored bound methods can be called later
bar on <__main__.Foo object at 0x10c3b6390>
>>> foo_bar()
bar on <__main__.Foo object at 0x10c3b6390>
バインドされたメソッドを格納できるということは、それらを属性として格納することもできることを意味します。バインドされたメソッドをバインドされたインスタンスに格納すると、バインドされていないメソッドのように見えます。ただし、実際には、格納されたバインドされたメソッドの動作は微妙に異なり、属性を許可する任意のオブジェクトに格納できます。
>>> foo.qux = foo.bar
>>> foo.qux
<bound method Foo.bar of <__main__.Foo object at 0x10c3b6390>>
>>> foo.qux is foo.qux # binding is not repeated on every lookup!
True
>>> too = Foo()
>>> too.qux = foo.qux # bound methods can be stored on other instances!
>>> too.qux # ...but are still bound to the original instance!
<bound method Foo.bar of <__main__.Foo object at 0x10c3b6390>>
>>> import builtins
>>> builtins.qux = foo.qux # bound methods can be stored...
>>> qux # ... *anywhere* that supports attributes
<bound method Foo.bar of <__main__.Foo object at 0x10c3b6390>>
Pythonに関する限り、バインドされたメソッドは通常の呼び出し可能なオブジェクトです。の方法であるかどうかを知る方法がないのと同じように、それがtoo.qux
方法であるtoo
かどうかを推測することもできませんtoo.__repr__
。