如果一个对象没有 `__dict__`,它的类是否必须有一个 `__slots__` 属性? [英] If an object doesn't have `__dict__`, does its class must have a `__slots__` attribute?
问题描述
来自https://stackoverflow.com/a/1529099/156458
<块引用>为了支持任意属性分配,一个对象需要一个__dict__
:与对象关联的字典,其中可以是任意属性存储.否则,就无处可放新属性.
object
的实例不携带 __dict__
-- 如果有的话,在可怕的循环依赖问题之前(因为 __dict__
,像大多数其他一切,继承自 object
;-),这将使每个带有字典的 Python 中的对象,这意味着许多开销当前没有或不需要字典的每个对象的字节数(本质上,所有没有可任意分配的对象属性没有或不需要字典).
...
当类具有 __slots__
特殊属性(字符串序列)时,则使用 class
语句(更准确地说,默认元类,type
code>) 并不是为该类的每个实例配备一个 __dict__
(因此具有任意属性的能力),只是一组有限的、刚性的槽"(基本上每个地方都可以保存对某个对象的一个引用)具有给定的名称.
如果一个对象没有 __dict__
,它的类是否必须有一个 __slots__
属性?
例如 object
的实例没有 __dict__
,
但是
<预><代码>>>>object.__slots__回溯(最近一次调用最后一次):文件<stdin>",第 1 行,位于 <module>AttributeError: 类型对象object"没有属性__slots__"那么为什么 object
的实例没有 __dict__
而 object
没有 __slots__
属性?
object
的实例是否有任何属性?
有多少种可能:
- 一个对象有
__dict__
,它的类有__dict__
但没有__slots__
- 一个对象没有
__dict__
,它的类有__slots__
- 一个对象没有
__dict__
,它的类没有__slots__
?
是否可以判断一个对象是否具有来自其类的 __dict__
?
- 如果它的类有
__slots__
,那么它就没有__dict__
- 如果它的类没有
__slots__
,我怎么知道它是否有__dict__
?
对于用户定义的类(在常规 Python 代码中使用 class
关键字定义),一个类将始终具有 __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__
,因为这对它们毫无意义.>
示例:
# 类有__slots__,实例没有__dict__DictLess 类:__slots__ = ()# 实例有 __dict__,类没有 __slots__DictOnly 类:经过# 类有 __slots__,实例有 __dict__ 因为 __slots__ 声明了它类 SlottedDict:__slots__ = '__dict__',# 类有 __slots__ 没有 __dict__ 槽,实例有它来自未槽的父类 DictFromParent(DictOnly):__slots__ = ()# 完全疯了:__slots__ 在类定义时生效,但是可以# 稍后删除,不改变类行为:NoSlotNoDict 类:__slots__ = ()del NoSlotNoDict.__slots__# 实例没有 __dict__,类没有 __slots__ 但行为就像它一样#(通过删除 __slots__ 并不能撤消使其开槽的机制)#拜托,请不要真的这样做# 没有实例 __dict__ 或类定义的 __slots__ 的内置类型:int().__dict__ # 引发 AttributeErrorint.__slots__ # 也会引发 AttributeError# 在实例上选择 __dict__ 的内置类型:导入功能工具functools.partial(int).__dict__ # 工作正常functools.partial.__slots__ # 引发 AttributeError
From https://stackoverflow.com/a/1529099/156458
To support arbitrary attribute assignment, an object needs a
__dict__
: a dict associated with the object, where arbitrary attributes can be stored. Otherwise, there's nowhere to put new attributes.An instance of
object
does not carry around a__dict__
-- if it did, before the horrible circular dependence problem (since__dict__
, like most everything else, inherits fromobject
;-), this would saddle every object in Python with a dict, which would mean an overhead of many bytes per object that currently doesn't have or need a dict (essentially, all objects that don't have arbitrarily assignable attributes don't have or need a dict)....
When the class has the
__slots__
special attribute (a sequence of strings), then theclass
statement (more precisely, the default metaclass,type
) does not equip every instance of that class with a__dict__
(and therefore the ability to have arbitrary attributes), just a finite, rigid set of "slots" (basically places which can each hold one reference to some object) with the given names.
If an object doesn't have __dict__
, does its class must have a __slots__
attribute?
For example an instance of object
doesn't have __dict__
,
>>> object().__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__dict__'
but
>>> object.__slots__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__slots__'
So why does an instance of object
not have __dict__
and object
has no __slots__
attribute?
Does an instance of object
have any attribute?
How many possibilities are there:
- an object has
__dict__
, and its class has__dict__
but no__slots__
- an object doesn't have
__dict__
, and its class has__slots__
- an object doesn't have
__dict__
, and its class doesn't have__slots__
?
Is it possible to tell if an object has __dict__
from its class?
- if its class has
__slots__
, then it doesn't have__dict__
- if its class doesn't have
__slots__
, how can I tell if it has__dict__
or not?
For user defined classes (defined using the class
keyword in regular Python code), a class will always have __slots__
on the class, __dict__
on the instance, or both (if one of the slots defined is '__dict__'
, or one of the user defined classes in an inheritance chain defines __slots__
and another one does not, creating __dict__
implicitly). So that's three of four possibilities covered for user defined classes.
Edit: A correction: Technically, a user-defined class could have neither; the class would be defined with __slots__
, but have it deleted after definition time (the machinery that sets up the type doesn't require __slots__
to persist after the class definition finishes). No sane person should do this, and it could have undesirable side-effects (full behavior untested), but it's possible.
For built-in types, at least in the CPython reference interpreter, they're extremely unlikely to have __slots__
(if they did, it would be to simulate a user-defined class, defining it doesn't actually do anything useful). A built-in type typically stores its attributes as raw C level values and pointers on a C level struct, optionally with explicitly created descriptors or accessor methods, which eliminates the purpose of __slots__
, which are just a convenient limited purpose equivalent of such struct games for user defined classes. __dict__
is opt-in for built-in types, not on by default (though the opt-in process is fairly easy; you need to put a PyObject*
entry somewhere in the struct and provide the offset to it in the type definition).
To be clear, __dict__
need not appear on the class for it to appear on its instances; __slots__
is class level, and can suppress the __dict__
on the instance, but has no effect on whether the class itself has a __dict__
; user defined classes always have __dict__
, but their instances won't if you're careful to use __slots__
appropriately.
So in short:
(Sane) User defined classes have at least one of __dict__
(on the instances) or __slots__
(on the class), and can have both. Insane user defined classes could have neither, but only a deranged developer would do it.
Built-in classes often have neither, may provide __dict__
, and almost never provide __slots__
as it is pointless for them.
Examples:
# 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
这篇关于如果一个对象没有 `__dict__`,它的类是否必须有一个 `__slots__` 属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!