Python 为什么需要def\uuu get\uuuu:return types.MethodType?

Python 为什么需要def\uuu get\uuuu:return types.MethodType?,python,Python,我在努力理解这一点 有没有人举个例子说明什么时候会出现这种情况/我为什么需要这种情况 您发布的代码用作描述符。 这有以下效果:如果一个类有一个描述符的对象,那么一个实例就有一个与该类中的对象同名的属性 如果设置该属性,将调用描述符的\uuuuu set\uuuuu(self、instance、value)命令 如果删除它,则调用描述符时,\uuu delete\uu(self,instance)函数 如果您试图接收存储在该属性中的数据,则会调用描述符的\uuu get\uuu(self、inst

我在努力理解这一点


有没有人举个例子说明什么时候会出现这种情况/我为什么需要这种情况

您发布的代码用作描述符。 这有以下效果:如果一个类有一个描述符的对象,那么一个实例就有一个与该类中的对象同名的属性

如果设置该属性,将调用描述符的
\uuuuu set\uuuuu(self、instance、value)
命令

如果删除它,则调用描述符时,
\uuu delete\uu(self,instance)
函数

如果您试图接收存储在该属性中的数据,则会调用描述符的
\uuu get\uuu(self、instance、owner)
方法。 (所有者是包含描述符对象的类)

self参数是描述符本身(就像python中的任何其他对象一样),instance参数是包含修改的属性的对象

因此,在这种情况下,接收具有底层
基元的属性的数据将导致py2的
类型。MethodType(self,instance)
或py3的
类型。MethodType(self,instance,owner)
,其中
self
是基元,
instance
是检索属性的对象,
owner
是保存
原语的类。(如前所述)

我希望我能帮上忙


python中的CodenameLambda

每当一个类定义了
\uuuuuu get\uuuuuu
\uuuu set\uuuuuuuu
\uuuuu delete\uuuuuuuu
时,就称之为描述符类。它们给出了类属性的“绑定”行为。这基本上意味着,每当您使用通常的点表示法通过类作为属性访问该对象时,它将根据调用的类型运行这些定义的方法之一。您发布的代码只定义了
\uuuuu get\uuuu
,这使它成为一个非数据描述符

还有一个dunder方法在这里被重写,它开始发挥作用,
\uuuuuu call\uuuu
这使您的类成为一个可调用的对象:

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
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
正在调用所有 两个“ops”列表中的字符串。在相同的
setattr
call
primitive
中 调用
getattr
,以检索相同的内置方法 类型
float
中的名称,将其作为初始
func
参数传入。现在,无论何时访问这些操作,它们都是绑定方法

因此,如果调用设置为
FloatNode
属性的其中一个“ops”:

>> FloatNode(1, []).__add__
<bound method __add__ of <__main__.FloatNode object at 0xb6fd61ec>>
浮动节点(1,[])。\u添加__
您将得到一个绑定方法,它封装了
原语
所具有的所有优点(即梯度函数)

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