是什么允许裸类实例具有可分配的属性?

Bog*_* M. 11 python python-3.x

我试图填补我对 Python 对象和类如何工作的理解上的空白。


object实例不支持以任何方式分配属性:

> object().a = 5
# or
> setattr(object(), 'a', 5)

AttributeError: 'object' object has no attribute 'a'
Run Code Online (Sandbox Code Playgroud)

我认为这是因为裸object实例不具有__dict__属性:

> '__dict__' in dir(object())

False
Run Code Online (Sandbox Code Playgroud)

然而,裸object实例确实有一个定义的__setattr__属性,所以这对我来说有点令人困惑:

> '__setattr__' in dir(object())

True
Run Code Online (Sandbox Code Playgroud)

另一方面,常规空类的实例具有属性分配的全部能力:

class B(object):
    pass

> B().a = 5
> setattr(B(), 'a', 5)
Run Code Online (Sandbox Code Playgroud)

我的问题是:如果直接继承的话object,实例和class B(object)实例之间有什么内在区别允许后者具有可分配的属性?Bobject

jac*_*cob 6

object()就像 Python 宇宙的基本粒子,是 Python 中所有对象(读取所有内容)的基类(或构建块)。因此,所述行为是合乎逻辑的,因为并非所有对象都可以(或应该)设置任意属性。例如,如果一个对象可以设置属性,那么它就没有意义NoneType,并且就像一样object()None对象也没有__dict__属性。事实上,两者唯一的区别是None对象具有__bool__属性。例如:

\n
n = None\no = object()\n\ntype(n)\n>>> <class \'NoneType\'>\n\nset(dir(n)) - set(dir(o))\n>>> {\'__bool__\'}\n\nisinstance(n, object)\n>>> True\n\nbool(n)\n>>> False\n
Run Code Online (Sandbox Code Playgroud)\n

继承object是自动的,并且就像任何其他继承方式一样,可以向子级添加自己的类方法和属性。正如您已经展示的那样, Python 自动添加__dict__自定义数据类型的属性。

\n

简而言之,__dict__对于没有自定义可写属性(即NoneType)的对象,添加对象的属性比删除它要容易得多。

\n

根据评论更新:

\n

原评论:

\n
\n

那么可以安全地假设它是__setattr__检查是否存在__dict__并相应地引发异常吗?\xe2\x80\x93\nbool3max

\n
\n

在CPython中,背后的逻辑object.__setattr__(self, name, value)是由Objects/object.c实现的_PyObject_GenericSetAttrWithDict(参见CPython源代码)。具体来说,如果name参数是字符串,则检查该对象__dict__在其插槽之一中是否有对象,并确保它已“准备好”(请参阅​​这一行)。

\n

对象的就绪状态由 确定PyType_Ready(),简要描述并引用自此处

\n
\n

在 C 中定义 Python 类型涉及使用您关心的值填充 PyTypeObject 结构的字段。我们将每个字段称为 \xe2\x80\x9cslot\xe2\x80\x9d。

\n

定义准备就绪后,我们将其传递给 PyType_Ready() 函数,该函数会执行许多操作,包括将大部分类型定义暴露给 Python\xe2\x80\x99s 属性查找机制。

\n
\n