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

时间:2017-10-04 22:33:39

标签: python python-3.x

来自https://stackoverflow.com/a/1529099/156458

  

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

     

object的实例不带__dict__ - 如果有的话,   在可怕的循环依赖问题之前(自__dict__起,就像大多数人一样)   其他一切,都继承自object ;-),这会让每一个人都感到厌烦   Python中带有dict的对象,这意味着许多人的开销   每个对象当前没有或需要dict的字节数   (基本上,所有不能任意分配的对象   属性不具备或需要字典。

     

...

     

当类具有__slots__特殊属性(字符串序列)时,class语句(更确切地说,默认元类,type)会不< / strong>为该类的每个实例配备__dict__(因此具有任意属性的能力),只是一组有限的,刚性的&#34;插槽&#34; (基本上每个人都可以拥有一个对象的一个​​引用的位置)具有给定的名称。

如果某个对象没有__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__

1 个答案:

答案 0 :(得分:6)

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

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

对于内置类型,至少在CPython参考解释器中,他们不太可能有__slots__(如果他们这样做,那就是模拟用户定义的class,定义它实际上并不任何有用的东西)。内置类型通常将其属性存储为原始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