一尘不染

如果对象不具有__dict__,则其类是否必须具有__slots__属性?

python

为了支持任意属性分配,对象需要一个__dict__:与对象关联的字典,可以在其中存储任意属性。否则,就无处放置新属性。

在可怕的循环依赖问题之前(因为它像大多数其他事物一样,都是从;-继承的),它的实例object不会携带__dict__-如果这样做的话,这会使python中的每个对象都受字典约束,这意味着开销当前没有或不需要字典的每个对象中有多少字节(基本上,所有不具有任意可分配属性的对象都没有或不需要字典)。__dict__``object

当类具有__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__'

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

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

的实例object具有任何属性吗?

有多少种可能性:

  • 一个对象具有__dict__,其类具有__dict__但没有__slots__
  • 对象不具有__dict__,其类具有__slots__
  • 一个对象没有__dict__,它的类也没有__slots__

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

  • 如果其类具有__slots__,则它不具有__dict__
  • 如果它的班级没有__slots__,我怎么知道它有__dict__没有?

阅读 242

收藏
2021-01-20

共1个答案

一尘不染

对于用户定义的类(使用class常规Python代码中的关键字定义),一个类将始终__slots__在该类,__dict__该实例上或同时在这两个类上(如果定义的插槽'__dict__'之一是,或在继承链中是用户定义的类之一)定义__slots__而另一个则没有,__dict__隐式创建)。因此,这是用户定义的类涵盖的四种可能性中的三种。

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

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

需要明确的是,__dict__不必出现在 类上 就可以使其出现在其 实例上__slots__是类级别的,并且可以抑制
实例__dict__上的,但对类本身是否具有;没有影响;用户定义的 始终具有,但是如果您谨慎使用它们的实例将不会。 __dict__
__dict__``__slots__

简而言之:

(合理)用户定义的类至少具有__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
2021-01-20