【问题标题】:Python __class__()Python __class__()
【发布时间】:2018-01-02 18:50:24
【问题描述】:

在 Python 的文档中,__class__ 被描述为一个属性。在对象type(元类)中,__class__ 似乎是一个方法。

如果我们这样做:

>>> class Foo:
        pass

>>> a = Foo()
>>> a.__class__ == type.__class__(a)
True

所以,我的问题是:

  1. 当我们调用a.__class__时,我们真的调用了type.__class__(a)方法吗?
  2. 这就是__class__ 不是a__dict__ 属性成员的原因吗?

【问题讨论】:

    标签: python python-3.x types python-internals object-model


    【解决方案1】:

    __class__ 是一个data descriptor object。 Python 核心对象上的许多属性都是作为描述符实现的。您应该将其视为实现细节,仅此而已。

    __class__ 是一个描述符,因为 Python 需要能够验证您分配给它的新值;分配给__class__ 有一定的限制,需要尊重,将__class__ 设为描述符是这样做的最有效方法。

    当您尝试访问对象的属性时,会自动找到并在类型上调用描述符对象。 instance.__class__ 将在类上找到并执行__class__ 描述符(通过搜索继承图中的所有类),通常以object.__dict__['__class__'].__get__(instance, type(instance)) 结尾(其中object 通常是__class__ 所在的第一个类属性位于type(instance).__mro__ 序列中);发生这种情况是因为 Python 将始终使用类型的 __getattribute__ 方法来查找属性,并且该方法知道如何处理在类和基上找到的描述符,以及查看 object.__dict__ 属性。因此,它们不依赖于对象 __dict__ 本身,而是依赖于对象类型,这是设计使然。

    现在,类对象也是可调用对象。这就是您创建实例的方式;对于给定的类Foo,你通过调用它来创建一个实例,所以Foo()instance.__class__ 只是对类对象的引用,就像 class_obj = Foo 会创建对类的引用一样。调用类对象会生成一个新实例,无论您使用什么引用来获取它。

    最后,type.__class__ 只是对type() 本身的引用:

    >>> type.__class__ is type
    True
    >>> type.__class__
    <class 'type'>
    >>> type(type)
    <class 'type'>
    

    那是因为type 是它自己的类型。 Python 类型系统的父子关系必须在某处停止,type 就是那个点。

    在您的示例中,a.__class__ 是对 Foo 类的引用。而type.__class__type 是同一个对象,所以你基本上是这样做的:

    Foo == type(a)
    

    确实如此,a 的类型是Foo

    【讨论】:

    • 感谢您的回答。现在,您说:instance.__class__ 将找到并执行 type(instance).__dict__['__class__'].__get__(instance, type(instance)) 但如果这样做:type(instance).__dict__ 没有 __ class__ 描述符,这让我想到了我的第一个问题,并假设描述符__ class__ 仅存在于对象 type 中,并被传递给它们的所有实例对象(所有类)。 ?
    • @maxfraguas:对不起,我让事情变得比我想要的更令人困惑。 object.__dict__['__class__'] 是描述符对象;所有类都继承自它。搜索整个类层次结构以查找此类属性(因此 next(t.__dict__['__class__'] for t in type(instance).__mro__ if '__class__' in t.__dict__).__get__(instance, type(instance)).
    • 谢谢@Matijn Pieters。在玩了一会儿之后,我在 object__dict__ 中找到了 __class__
    猜你喜欢
    • 2012-03-25
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    相关资源
    最近更新 更多