2016-05-27 22 views
2

単純な関数__get__の目的は何ですか、なぜ記述子クラス__get__と異なった振る舞いをするのですか?単純な関数の__get__の目的

マイ調査:

import inspect 

def a(x, y): 
    return x + y 

def wr(f): 
    def wrapper(*args, **kwargs): 
     print f.__name__, 'called with', args, kwargs 
     return f(*args, **kwargs) 
    return wrapper 

print inspect.getsource(a) 
# def a(x, y): 
#  return x + y 

print inspect.getsource(a.__get__) # we cannot inspect it because it is a method-wrapper 
# Traceback (most recent call last): 
# ... 
#  'function, traceback, frame, or code object'.format(object)) 
# TypeError: <method-wrapper '__get__' of function object at 0x7fd43591e140> is not a module, class, method, function, traceback, frame, or code object 

a.__get__ = wr(a.__get__) # replace with function that delegates work and prints passed arguments 
a2 = a.__get__(2) # we can use __get__ for functools.partial purposes 
# __get__ called with (2,) {} 

print a.__class__, a2.__class__ # it looks like a is a normal function and a2 is a bound function, but there is no instance 
# <type 'function'> <type 'instancemethod'> 

print 'a2 result:', a2(3) 
# a2 result: 5 

print inspect.getsource(a2) # source the same as function a 
# def a(x, y): 
#  return x + y 

私たちが知っている記述子クラス__get__メソッドのシグネチャobject.__get__(self, instance, owner)とそれが機能にa.__get__署名と一致しないことのように見えます。

答えて

1

Python関数は記述子です。メソッドオブジェクトの作成方法です。 obj.methodを実行すると、記述子プロトコルが有効になり、関数の__get__メソッドが呼び出されます。これはバインドされたメソッドを返します。

これは、インスタンスメソッドとしてa2が表示されている理由です。 a.__get__(2)を実行するときは、 "instance"引数として2__get__に渡しています。 print(a2)を実行すると、<bound method ?.a of 2>と表示され、がオブジェクト2のバインドされたメソッドだとPythonが判断したことを示します。

owner引数は、記述子プロトコル(または少なくとも関数の実装)では省略可能です。なぜなら、1つの引数で__get__を呼び出すことができるからです。 と呼び、a.__get__(2, 1)と呼び、同様のオブジェクトを戻します。

+0

引数が渡されたとして、我々は機能上の(自己、例えば、所有者) '__get __'を呼び出すとき: 'self'は関数自体であり、インスタンスは' 2'であり、ownerは 'None'です。オプションであるためです。 関数 '__get__'メソッドは、関数自身が第1引数としてインスタンス(' self')を期待しているので、第1引数として常にインスタンスを渡すバインドされたメソッドを返します。インスタンスの代わりに '2'を渡すので、' a2'関数の最初の引数として '2'が渡されます。私は正しいですか? –

+0

@ user1915011:私はあなたを理解しているか分からない。 'a .__ get__'は' a'が受け入れる引数を実際には気にしません。 'a .__ get__'に渡される' self'は、あなたが言うように、 'a'自身の関数です。 'a .__ get__'は' a'が受け入れる引数を調べるために "チェック"しません。 'a'が関数の場合、' a____'をインスタンス引数として渡さない限り、 'a .__ get__' * always *はバウンドメソッドオブジェクトを返します(アンバインドされたメソッドを返します)。 – BrenBarn

1

__get__は標準ディスクリプタ__get__です。データモデルには反映されませんが、__get__への引数ownerは、非Noneinstanceの追加情報を提供しないため、オプションでよく行われます。これは記述子プロトコルに違反しません。

機能のが__get__は通常__get__方法は属性アクセスの一部として、呼び出される通常の方法で記述子と呼ばれている:

class Foo(object): 
    def bar(self): 
     return 3 

foo = Foo() 

# The following attribute access calls bar.__get__(foo, Foo) to create a method object. 
bar_method = foo.bar 
関連する問題