Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
220 views
in Technique[技术] by (71.8m points)

Python method-wrapper type?

What is the method-wrapper type in Python 3? If I define a class like so:

class Foo(object):
    def __init__(self, val):
        self.val = val
    def __eq__(self, other):
        return self.val == other.val

And then do:

Foo(42).__eq__

I get:

<bound method Foo.__eq__ of <__main__.Foo object at 0x10121d0>>

But if I do (in Python 3 ):

Foo(42).__ne__

I get:

<method-wrapper '__ne__' of Foo object at 0x1073e50>

What is a "method-wrapper" type?

Edit: sorry to be more accurate: class method-wrapper is the type of __ne__, as if I do:

>>> type(Foo(42).__ne__)
<class 'method-wrapper'>

Whereas the type of __eq__ is:

>>> type(Foo(42).__eq__)
<class 'method'>

Furthermore method-wrapper seems to be the type of any undefined magic method on a class (so __le__, __repr__, __str__ etc if not explicitly defined will also have this type).

What I am interested in is how the method-wrapper class is used by Python. Are all "default implementations" of methods on a class just instances of this type?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It appears that the type <method-wrapper ..> is used by CPython for methods implemented in C code. Basically the type doesn't wrap another method. Instead it wraps a C-implemented function as an bound method. In this way <method-wrapper> is exactly like a <bound-method> except that it is implemented in C.

In CPython there are two special types related to this.

  • <slot wrapper> Which (at least) wraps a C-implemented function. Behaves like an <unbound method> in CPython 2 (at least sometimes) or a <function> in CPython 3
  • <method-wrapper> Which wraps a C-implemented function as an bound method. Instances of this type have an __self__ attribute__ which is used as first argument when it is called.

If you have a <slot wrapper> you bind it to an object with __get__ to get an <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")  

You can call __get__ on any function-like object in Python to get an <bound method> or <method-wrapper>. Note __get__ on both of these types will simply return self.

Python 3

The type object in CPython 3 have C-implementations for both __ne__ and __eq__, and any of the other comparison operators. Thus object.__ne__ returns a <slot wrapper> for this operator. Likewise object().__ne__ returns a <method-wrapper> which can be used to compare the this object.

Since you have not defined __ne__ in your class you get a bound method (as <method-wrapper>) which is the C-implemented function for instance of object (included derived instances). My bet is that this C function will check if you have defined any __eq__, call this, and then not the result.

Python 2 (not asked but answered)

Python 2 behaves significantly different here. Since we have the concept of unbound methods. which require that you call them with the proper first-argument type, both <slot wrapper> and <method-wrapper> have an __objclass__ which is the type the first-argument must be an instance of.

More over: Python 2 does not have any implementations of comparisons operators for the object type. Thus object.__ne__ is not a function to compare objects. Rather, interesting, the type type which is the metaclass of object does have an C-implemented __ne__ operator. Thus you get an bound method from object.__ne__ that will try to compare the type object with any other type (or object).

Thus object().__ne__ will actually fail with an AttributeError since object does not define any such method. Given that object() == object() actually works (giving False), I would guess that CPython 2 have special-cases in the interpreter for comparison of objects. Once more we see that CPython 3 have cleaned up some less-fortunate implementation details of Python 2.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...