如果一个对象没有`__dict__`,它的类必须有一个`__slots__`属性吗?

Tim*_*Tim 3 python python-3.x

来自/sf/answers/107036961/

为了支持任意属性赋值,对象需要__dict__:与对象关联的字典,其中可以存储任意属性.否则,无处可放新属性.

一个实例object没有携带__dict__- 如果确实如此,在可怕的循环依赖问题之前(因为__dict__,像大多数其他所有东西一样,继承自object;-),这会使Python中的每个对象都带有一个dict,这意味着开销当前没有或不需要dict的每个对象的许多字节(实质上,所有没有任意可分配属性的对象都没有或不需要dict).

...

当类具有__slots__特殊属性(字符串序列),那么class语句(更准确地说,默认元类type)并没有装备有该类的每个实例__dict__(有任意属性,因此的能力),只是一个有限,具有给定名称的刚性"槽"集(基本上每个可以对一些对象保持一个引用的位置).

如果一个对象没有__dict__,它的类必须有一个__slots__属性吗?

例如,object没有的实例__dict__,

>>> object().__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__dict__'
Run Code Online (Sandbox Code Playgroud)

>>> object.__slots__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__slots__'
Run Code Online (Sandbox Code Playgroud)

那么,为什么一个实例object没有__dict__object有没有 __slots__属性?

一个实例object有任何属性吗?

有多少种可能性:

  • 一个对象有__dict__,它的类有__dict__但没有__slots__
  • 一个对象没有__dict__,它的类有__slots__
  • 一个对象没有__dict__,它的类没有__slots__

是否可以判断对象是否__dict__来自其类?

  • 如果它的类有__slots__,那么它没有__dict__
  • 如果它的班级没有__slots__,我怎么知道它是否有__dict__

Sha*_*ger 8

对于用户定义的类(使用class常规Python代码中的关键字定义),类将始终包含__slots__在类,__dict__实例或两者上(如果定义了其中一个槽'__dict__',或者是继承链中的一个用户定义的类)定义__slots__,另一个不定义,__dict__隐式创建).因此,用户定义的类涵盖了四种可能性中的三种.

编辑:更正:从技术上讲,用户定义的类可能既没有 ; 该类将定义为__slots__,但在定义时间之后将其删除(设置类型的机制__slots__在类定义完成后不需要保留).没有理智的人应该这样做,它可能有不良的副作用(完整的行为未经测试),但它是可能的.

对于内置类型,至少在CPython引用解释器中,它们不可能具有__slots__(如果它们,它将模拟用户定义的类,定义它实际上没有任何有用的事情).内置类型通常将其属性存储为原始C级别值和C级结构上的指针,可选地使用显式创建的描述符或访问器方法,这样可以消除目的__slots__,这只是一种方便的有限目的,相当于这样的结构游戏.用户定义的类.__dict__选择加入内置类型,默认情况下不启用(尽管选择加入过程相当简单;您需要PyObject*在结构中的某处放置一个条目,并在类型定义中为其提供偏移量).

为了清楚起见,__dict__不需要在中出现它以显示在它的实例上 ; __slots__是一流水平,并能抑制__dict__情况下,但对类本身是否具有没有影响__dict__; 用户定义的总是有__dict__,但如果你小心使用它们,它们的实例将不会__slots__.

简而言之:

(Sane)用户定义的类至少有一个__dict__(在实例上)或__slots__(在类上),并且可以同时具有这两个类.疯狂的用户定义的类可以既没有,但只是一个疯狂的开发商会做到这一点.

内置类通常既没有,可能提供__dict__,几乎从不提供,__slots__因为它对他们来说毫无意义.

例子:

# Class has __slots__, instances don't have __dict__
class DictLess:
    __slots__ = ()

# Instances have __dict__, class lacks __slots__
class DictOnly:
    pass

# Class has __slots__, instances have __dict__ because __slots__ declares it
class SlottedDict:
    __slots__ = '__dict__',

# Class has __slots__ without __dict__ slot, instances have it anyway from unslotted parent
class DictFromParent(DictOnly):
    __slots__ = ()

# Complete insanity: __slots__ takes effect at class definition time, but can
# be deleted later, without changing the class behavior:
class NoSlotNoDict:
    __slots__ = ()
del NoSlotNoDict.__slots__
# Instances have no __dict__, class has no __slots__ but acts like it does
# (the machinery to make it slotted isn't undone by deleting __slots__)
# Please, please don't actually do this

# Built-in type without instance __dict__ or class defined __slots__:
int().__dict__  # Raises AttributeError
int.__slots__   # Also raises AttributeError

# Built-in type that opts in to __dict__ on instances:
import functools
functools.partial(int).__dict__ # Works fine
functools.partial.__slots__ # Raises AttributeError
Run Code Online (Sandbox Code Playgroud)