Skip to main content
 首页 » 编程设计

types之Python方法包装器类型

2024年09月07日18dudu

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 的一些不太幸运的实现细节。