2016-04-23 92 views

回答

2

在蟒蛇当一个类定义要么__get____set__,或者__delete__据说是一个描述符类。这些给出了一个类属性“绑定”的行为。这基本上意味着无论何时通过使用通常点符号的类通过类访问该对象作为属性,它都将根据所调用的类型运行一个定义的方法。您发布的代码只定义了__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 

正如你所看到的,你可以对实例调用,就像你喜欢的只是像任何其他可调用函数(例如函数)。我要回顾一下,因为描述符类返回types.MethodType(self, obj)types.MethodType(self, obj, objtype),具体取决于您使用的是哪个Python版本。

MethodType绑定其第一个参数,必须将其第一个参数调用到它的第二个参数,该参数是一个类实例。基本上,您每次访问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) 

但作为一个描述符类在这里:

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))) 

在这里,你可以看到类FloatNode呼吁setattr来自两个“操作”列表的所有 字符串。在同样的setattr调用primitive是 打电话给getattr,该调用检索相同 名称的类型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)方法。 (所有者是包含描述符对象的类)

自参数是描述符本身(就像在python中的任何其他对象一样),而实例参数是包含被修改属性的对象。

因此,在这种情况下,接收的属性的数据与下面primitive导致types.MethodType(self, instance)用于PY2或types.MethodType(self, instance, owner)在PY3,其中self是原始的,instance是的属性被检索出的目标和owner是类保持primitive对象。 (如前所述)

我希望我能帮上忙,

CodenameLambda