Python 3 中的方法包装器类型是什么?如果我这样定义一个类:
class Foo(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
然后做:
Foo(42).__eq__
我得到:
<bound method Foo.__eq__ of <__main__.Foo object at 0x10121d0>>
但如果我这样做(在 Python 3 中):
Foo(42).__ne__
我得到:
<method-wrapper '__ne__' of Foo object at 0x1073e50>
什么是“方法包装器”类型?
编辑:抱歉更准确:
class method-wrapper
是
__ne__
的类型,好像我这样做:
>>> type(Foo(42).__ne__)
<class 'method-wrapper'>
而
__eq__
的类型是:
>>> type(Foo(42).__eq__)
<class 'method'>
此外
method-wrapper
似乎是类上任何未定义的魔法方法的类型(所以
__le__
,
__repr__
,
__str__
等如果没有明确定义也会有这种类型)。
我感兴趣的是
method-wrapper
类由 Python 使用。类上方法的所有“默认实现”都只是这种类型的实例吗?
请您参考如下方法:
似乎类型 <method-wrapper ..>
CPython 将其用于在 C 代码中实现的方法。基本上该类型不包装另一种方法。相反,它将 C 实现的函数包装为绑定(bind)方法。这样<method-wrapper>
与 <bound-method>
完全一样除了它是用C实现的。
在 CPython 中有两种与此相关的特殊类型。
<slot wrapper>
其中(至少)包装了一个 C 实现的函数。表现得像 <unbound method>
在 CPython 2 中(至少有时)或 <function>
在 CPython 3 <method-wrapper>
它将 C 实现的函数包装为绑定(bind)方法。这种类型的实例有 __self__
调用时用作第一个参数的属性__。 如果您有
<slot wrapper>
你用
__get__
将它绑定(bind)到一个对象上获取
<method-wrapper>
:
# returns a <slot_wrapper> on both CPython 2 and 3
sw = object.__getattribute__
# returns a <method-wrapper>
bound_method = sw.__get__(object())
# In this case raises AttributeError since no "some_attribute" exists.
bound_method("some_attribute")
您可以调用
__get__
在 Python 中的任何类似函数的对象上获取
<bound method>
或
<method-wrapper>
.备注
__get__
这两种类型都会简单地返回 self.
python 3
类型
object
在 CPython 3 中,
__ne__
都有 C 实现和
__eq__
,以及任何其他比较运算符。因此
object.__ne__
返回
<slot wrapper>
对于这个运营商。同样
object().__ne__
返回
<method-wrapper>
可用于比较 this 对象。
由于您尚未定义
__ne__
在您的类中,您会得到一个绑定(bind)方法(如
<method-wrapper>
),它是对象实例(包括派生实例)的 C 实现函数。我敢打赌,这个 C 函数将检查您是否定义了任何
__eq__
,调用这个,然后不是结果。
Python 2(未问但已回答)
Python 2 在这里的表现明显不同。因为我们有未绑定(bind)方法的概念。这要求您使用正确的第一个参数类型来调用它们,两者都是
<slot wrapper>
和
<method-wrapper>
有一个
__objclass__
这是第一个参数必须是实例的类型。
此外:Python 2 没有任何
object
比较运算符的实现。类型。因此
object.__ne__
不是比较对象的函数。更有趣的是,类型
type
这是
object
的元类确实有一个 C 实现的
__ne__
运算符(operator)。因此,您会从
object.__ne__
获得绑定(bind)方法将尝试比较类型
object
与任何其他类型(或对象)。
因此
object().__ne__
实际上会失败并返回
AttributeError
自从
object
没有定义任何这样的方法。鉴于
object() == object()
实际上有效(给出 False),我猜 CPython 2 在解释器中有用于比较对象的特殊情况。
我们再次看到 CPython 3 已经清理了 Python 2 的一些不太幸运的实现细节。