如果一个对象没有 `__dict__`,它的类是否必须有一个 `__slots__` 属性? [英] If an object doesn't have `__dict__`, does its class must have a `__slots__` attribute?

查看:34
本文介绍了如果一个对象没有 `__dict__`,它的类是否必须有一个 `__slots__` 属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

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

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

...

当类具有 __slots__ 特殊属性(字符串序列)时,则使用 class 语句(更准确地说,默认元类,typecode>) 并不是为该类的每个实例配备一个 __dict__(因此具有任意属性的能力),只是一组有限的、刚性的槽"(基本上每个地方都可以保存对某个对象的一个​​引用)具有给定的名称.

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

例如 object 的实例没有 __dict__,

<预><代码>>>>object().__dict__回溯(最近一次调用最后一次):文件<stdin>",第 1 行,位于 <module>AttributeError: '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 from object;-), 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 the class 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆