2016-04-23 14 views
2

私はこのblock of codedef __get__が必要な理由:戻り値の型。型名?

class primitive(object): 
    ... 
    def __get__(self, obj, objtype): 
     if sys.version_info >= (3,): 
      def __get__(self, obj, objtype): 
       return types.MethodType(self, obj) 
     else: 
      def __get__(self, obj, objtype): 
       return types.MethodType(self, obj, objtype) 

私はこれを必要とする理由、これは/出てくるだろうというとき、誰もが一例を持っていますを理解しようとしていますか?

答えて

2

、私は助けることができる願っています。これらは、クラス属性 "バインディング"動作を与えます。これは基本的には、通常、ドット表記を使用してクラスを通して属性としてオブジェクトにアクセスするたびに、呼び出されるタイプに応じて定義されたメソッドを実行します。投稿したコードは__get__と定義されているため、非データ記述子になります。

場に出るここで上書き別dunder方法があり、__call__これはあなたのクラスの呼び出し可能オブジェクトになり:あなたが見ることができるように、あなたが同じくらいあなただけの好きなようにインスタンス上で電話をかけることができ

Class CallableClass(object): 

    def __init__(self, fun): 
     self.fun = fun 

    def __call__(self, *args): 
     return self.fun(*args) 

>>> cc = CallableClass(lambda *args: return sum(args)) 
>>> cc(1, 2, 3) 
6 
>>> cc(0) 
0 

を他の呼び出し可能関数(関数など)と同様です。記述子クラスは、使用しているPythonのバージョンに応じてtypes.MethodType(self, obj)またはtypes.MethodType(self, obj, objtype)を返すので、これを処理します。

MethodTypeは、第1引数をバインドします。この第1引数は、クラスインスタンスである2番目の引数に呼び出す必要があります。基本的には、primitive記述子オブジェクトにアクセスするたびに、クラスインスタンスオブジェクトにバインドされたメソッドを作成しています。

ここでの「デスクリプタ」機能は、クラス属性として使用されている場合にのみ実際に使用され、primitiveドキュメントを読むと、クラスがデコレータとして機能をラップすることが記載されています。

@primitive 
def merge_tapes(x, y): return x 
merge_tapes.defgrad(lambda ans, x, y : lambda g : g) 
merge_tapes.defgrad(lambda ans, x, y : lambda g : g, argnum=1) 

しかし、ここで記述クラスとして使用:あなたはFloatNodesetattrを呼び出しているクラスを見ることができるようにここで

differentiable_ops = ['__add__', '__sub__', '__mul__', '__pow__', '__mod__', 
         '__neg__', '__radd__', '__rsub__', '__rmul__', '__rpow__', 
         '__rmod__', DIV, RDIV] 

nondifferentiable_ops = ['__eq__', '__ne__', '__gt__', '__ge__', '__lt__', '__le__',] 
for float_op in differentiable_ops + nondifferentiable_ops: 
    setattr(FloatNode, float_op, primitive(getattr(float, float_op))) 

一部の行は、あなたがデコレータとしてアクションでそれを見ることができますダウン2つの "操作"リストのすべての 文字列にその同じsetattrの呼び出しprimitiveは であり、同じ という名前の組み込みメソッドをタイプfloatから取得して、func引数として渡します。これらの操作のいずれかにアクセスするたびに、バインドされたメソッドになります。

ですから、FloatNodeの属性として設定されたものを「OPS」のいずれかに呼び出す場合:

>> FloatNode(1, []).__add__ 
<bound method __add__ of <__main__.FloatNode object at 0xb6fd61ec>> 

あなたはprimitiveが保持するすべての利点をカプセル化するバインド方法を取得します(つまり、勾配関数) 。

0

あなたが投稿したコードは、ディスクリプタとして使用されます。 これには次のような影響があります。クラスに記述子のオブジェクトがある場合、インスタンスにはそのクラスのオブジェクトと同じ名前の属性があります。

この属性を設定すると、ディスクリプタの__set__(self, instance, value)コマンドが呼び出されます。

削除すると、記述子が呼び出された場合は__delete__(self, instance)が機能します。

そして、その属性に格納されているデータを受け取ろうとすると、ディスクリプタの__get__(self, instance, owner)メソッドが呼び出されます。 (所有者は記述子オブジェクトを含むクラスです)

self引数は記述子自体です(pythonの他のオブジェクトと同様)。インスタンス引数は変更された属性を含むオブジェクトです。

そこでPY2またはselfプリミティブであるPY3、でtypes.MethodType(self, instance, owner)instancetypes.MethodType(self, instance)における根本的primitive結果と属性のデータを受信し、この場合には、その者の属性が取得されたオブジェクトであり、ownerクラスを保持していますprimitiveオブジェクトです。クラスは、どちらかの定義__get____set__、または__delete__記述子クラスと言われるたび

(先に説明したように)私はPythonで

CodenameLambda