3

このコードがあります:

class B:
    def f(self):
        pass

print(B.f) # <function B.f at 0xb711977c>
print(B().f) # <bound method B.f of <__main__.B object at 0xb71774cc>>

fクラスオブジェクトから関数にアクセスすると通常の関数が返されるが、クラスインスタンスからこの関数にアクセスするとバインドされたメソッドが返されることをインタープリターはどのように認識しますか? __get__オブジェクトを関数にバインドするために使用される関数があることを読みましたが、これはクラスおよびクラスインスタンスに対して内部的にどのように機能しますか?

4

1 に答える 1

1

関数は記述子として実装されます。ドキュメントを引用するには:

一般に、記述子は「バインディング動作」を持つオブジェクト属性であり、その属性アクセスは記述子プロトコルのメソッドによってオーバーライドされます。それらのメソッドは、、、__get__()および__set__()です__delete__()。これらのメソッドのいずれかがオブジェクトに対して定義されている場合、それは記述子と呼ばれます。

アイデアは、メソッドが属性がどのよう__get__にフェッチされたかを識別できるようにすることです。次の簡単な例を考えてみましょう。

>>> class Descriptor(object):
...     def __get__(self, obj, type=None):
...         print '__get__(%r, %r)' % (obj, type)
...
>>> class A(object):
...     desc = Descriptor()
...
>>> A.desc
__get__(None, <class '__main__.A'>)
>>> A().desc
__get__(<__main__.A object at 0x020F5B50>, <class '__main__.A'>)

ご覧のとおり、__get__ドキュメントで説明されているように、objパラメーターにより、クラスまたはインスタンスを介した属性アクセスを区別できます。関数属性にアクセスするときに、同じメカニズムを Python の内部で使用して、バインドされたメソッドまたはバインドされていないメソッドを返すことができます。

実際には:

>>> class A:
...     def f(self):
...             pass
...
>>> A.f.__get__(None, A)
<unbound method A.f>
>>> A.f.__get__(A(), A)
<bound method A.f of <__main__.A instance at 0x022082D8>>

これはすべて Python 2.x の例ですが、私が知る限り、バインドされていないメソッドが通常の関数であることを除いて、Python 3.x でも同じように機能します。

于 2013-05-30T16:45:42.773 に答える