Python 2/3:为什么类型(Foo .__ init__)不同?

时间:2014-08-10 12:51:01

标签: python python-2.7 python-3.x types

考虑课程:

Foo(object):
    def __init__(self):
        pass

在Python 2上执行type(Foo.__init__)

Python 2.7.5 (default, Mar  9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(object):
...     def __init__(self):
...             pass
...
>>> type(Foo.__init__)
<type 'instancemethod'>

在Python 3上执行type(Foo.__init__)

Python 3.4.1 (default, May 19 2014, 13:10:29)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(object):
...     def __init__(self):
...             pass
...
>>> type(Foo.__init__)
<class 'function'>

为什么{2}和3上的type(Foo.__init__)返回不同?

1 个答案:

答案 0 :(得分:2)

如果您要求更改,则简短版本位于What's New in 3.0

  

已从语言中删除“未绑定方法”的概念。当将方法作为类属性引用时,您现在将获得一个普通的函数对象。

更详细:

函数对象是descriptor__get__返回一个方法。在Python 2.x中,它看起来像这样(在纯Python伪代码中,稍微简化):

class FunctionType(object):
    # other stuff
    def __get__(self, instance, cls):
        return MethodType(func=self, instance=instance, cls=cls)

class MethodType(object):
    def __init__(self, func, instance, cls):
        self.__func__, self.__instance__, self.__class__ = func, instance, cls
    def __call__(self, *args, **kwargs):
        if self.__self__ is not None:
            return self.__func__(self.__self__, *args, **kwargs)
        else:
            return self.__func__(*args, **kwargs)

因此,当您编写Foo.__init__时,您将获得未绑定的方法MethodType(__init__, None, Foo)

在3.x中,它看起来像这样:

class FunctionType(object):
    # other stuff
    def __get__(self, instance, cls):
        if instance is not None:
            return MethodType(func=self, instance=instance)
        else:
            return self

class MethodType(object):
    def __init__(self, func, instance):
        self.__func__, self.__instance__, self.__class__ = func, instance, type(instance)
    def __call__(self, *args, **kwargs):
        return self.__func__(self.__self__, *args, **kwargs)

有关完整详细信息,请参阅“可调用类型”下3.x2.x的参考文档中的标准层次结构。


如果你问为什么它被改变了......好吧,据我记得,没有太多讨论这个 - 没有PEP,没有长时间讨论python-dev或-ideas等等 - 它只在文档中给出了一行。

但推理似乎很明显。未绑定的方法不是特别有用;它们只是额外的脚手架,提供与它们包装的函数完全相同的行为。*它们仅在2.2-2.7中用于更好地模拟经典类的行为**和/或因为它似乎更容易实现和/或因为在设计的早期,你不清楚你可以在没有它的情况下实现像@classmethod这样的东西,当Guido远远地意识到那里没有问题的时候,就更容易离开设计,因为他最初写的。


*绑定方法的CPython实现添加isinstance检查以验证第一个参数是self.__class__,但是没有明确记录,没有人编写依赖它的代码,它对调试没有任何帮助。

**如果你想知道为什么经典课程按他们的方式工作,你必须深入了解Guido的Python History博客 - 如果你有时间,所有这些都值得一读。