、私は助けることができる願っています。これらは、クラス属性 "バインディング"動作を与えます。これは基本的には、通常、ドット表記を使用してクラスを通して属性としてオブジェクトにアクセスするたびに、呼び出されるタイプに応じて定義されたメソッドを実行します。投稿したコードは__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)
しかし、ここで記述クラスとして使用:あなたはFloatNode
はsetattr
を呼び出しているクラスを見ることができるようにここで
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
が保持するすべての利点をカプセル化するバインド方法を取得します(つまり、勾配関数) 。