Python 3中的方法包装器类型是什么?如果我这样定义一个类:
class Foo(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
Run Code Online (Sandbox Code Playgroud)
然后做:
Foo(42).__eq__
Run Code Online (Sandbox Code Playgroud)
我明白了:
<bound method Foo.__eq__ of <__main__.Foo object at 0x10121d0>>
Run Code Online (Sandbox Code Playgroud)
但如果我这样做(在Python 3中):
Foo(42).__ne__
Run Code Online (Sandbox Code Playgroud)
我明白了:
<method-wrapper '__ne__' of Foo object at 0x1073e50>
Run Code Online (Sandbox Code Playgroud)
什么是"方法包装"类型?
编辑:抱歉更准确:class method-wrapper是类型__ne__,就像我做的那样:
>>> type(Foo(42).__ne__)
<class 'method-wrapper'>
Run Code Online (Sandbox Code Playgroud)
而类型__eq__是:
>>> type(Foo(42).__eq__)
<class 'method'>
Run Code Online (Sandbox Code Playgroud)
此外,method-wrapper似乎是类上任何未定义的魔术方法的类型(因此__le__,如果没有明确定义__repr__,则__str__等也将具有此类型).
我感兴趣的是method-wrapperPython 如何使用该类.类的方法的所有"默认实现"都只是这种类型的实例吗?
Gar*_*tty 25
这是因为Python 3中不存在"未绑定方法".
在Python 3000中,已删除未绑定方法的概念,表达式"A.spam"返回普通函数对象.事实证明,第一个参数必须是A的一个实例的限制在诊断问题时很少有用,并且经常成为高级用法的障碍 - 有些人称之为"鸭子打字自我",这似乎是一个恰当的名称. (资源)
在Python 2.x中,我们绑定了方法和未绑定的方法.绑定方法绑定到一个对象,这意味着当它被调用时,它将对象实例作为第一个变量(self通常)传递.一个未绑定的方法是函数是一个方法,但没有它所属的实例 - 如果将一个对象实例以外的东西传递给该方法,它将抛出一个错误.
现在,在3.x中,这已经改变了.当您请求对象的方法时,它不是绑定/未绑定的方法,而是返回函数对象,但是包装在传递实例变量的包装函数中.这样就不需要区分绑定和未绑定的方法了. - 绑定方法是包装的,未绑定的方法不包装.
澄清差异:
2.X:
a = A()
f = A.method # f is an unbound method - you must pass an instance of `A` in to it as the first argument.
f = a.method # f is a bound method, bound to the instance `a`.
Run Code Online (Sandbox Code Playgroud)
3.X:
a = A()
f = A.method # f is a function
f = a.method # f is a wrapped function with it's first argument filled with `a`.
Run Code Online (Sandbox Code Playgroud)
a.method 可以被认为是:
def method-wrapper():
A.method(a)
Run Code Online (Sandbox Code Playgroud)
有关这方面的更多信息,请查看Guido的博客 - Python的历史.
编辑:
所以,这一切都适用的原因是,这里__ne__()没有被覆盖 - 它处于默认状态,这是一个身份检查,用C(第980行)实现.包装器用于为该方法提供上述功能.
dri*_*iax 23
似乎<method-wrapper ..>CPython使用该类型用于在C代码中实现的方法.基本上该类型不包含另一种方法.相反,它将C实现的函数包装为绑定方法.这种方式<method-wrapper>完全像a,<bound-method> 除了它是用C实现的.
在CPython中有两种与此相关的特殊类型.
<slot wrapper>哪个(至少)包装了C实现的函数.<unbound method>在CPython 2(至少有时)或<function>CPython 3中表现得像<method-wrapper>其中将C实现的函数包装为绑定方法.这种类型的实例有一个__self__attribute__,它在被调用时用作第一个参数.如果你有一个<slot wrapper>绑定到一个对象,__get__得到一个<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")
Run Code Online (Sandbox Code Playgroud)
您可以__get__在Python中调用任何类似函数的对象来获取<bound method>或<method-wrapper>.__get__关于这两种类型的注意事项只会返回self.
类型object中的CPython 3具有C-实现两个__ne__和__eq__,以及任何其他的比较运算符.因此object.__ne__返回<slot wrapper>此运算符的a.同样object().__ne__返回一个<method-wrapper>可用于比较此对象的a.
由于您尚未__ne__在类中定义,因此您将获得一个绑定方法(as <method-wrapper>),它是对象(包含派生实例)的C实现函数.我敢打赌,这个C函数将检查你是否定义了任何__eq__,调用它,然后不是结果.
Python 2在这里表现出很大的不同.因为我们有未绑定方法的概念.这要求您使用正确的第一个参数类型调用它们,<slot wrapper>并且<method-wrapper>具有__objclass__哪个是first-argument必须是其实例的类型.
更多内容:Python 2没有任何object类型的比较运算符实现.因此object.__ne__,不是比较对象的函数.相反,有趣的type是,元类的类型object确实有一个C实现的__ne__运算符.因此,您将获得一个绑定方法object.__ne__,尝试将类型object与任何其他类型(或对象)进行比较.
因此object().__ne__实际上将失败,AttributeError因为object没有定义任何这样的方法.鉴于object() == object()实际上有效(给出False),我猜测CPython 2在解释器中有特殊情况用于比较对象.我们再次看到CPython 3已经清理了Python 2的一些不那么幸运的实现细节.
| 归档时间: |
|
| 查看次数: |
16554 次 |
| 最近记录: |