子类中的 __slots__ 继承实际上是如何工作的?
在 关于槽的 Python 数据模型参考部分 中,有一个关于使用的注释列表__slots__
。我对第 1 条和第 6 条感到非常困惑,因为它们似乎相互矛盾。
第一项:
- 当从没有
__slots__
,__dict__
属性 那个班级的永远是 可访问,因此__slots__
子类中的定义是 无意义的。
第六项:
__slots__
的操作 声明仅限于类 它是在哪里定义的。因此, 子类将有一个__dict__
除非他们还定义了 __slots__ (其中必须仅包含任何名称 额外的插槽)。
在我看来,这些项目可以更好地措辞或通过代码显示,但我一直在努力解决这个问题,但仍然感到困惑。我确实了解 __slots__
应该如何使用,并且我我试图更好地了解它们是如何工作的。
问题:
有人可以用通俗易懂的语言向我解释一下子类化时槽继承的条件是什么吗?
(简单的代码示例会有所帮助,但不是必需的。)
In the Python data model reference section on slots there is a list of notes on using __slots__
. I am thoroughly confused by the 1st and 6th items, because they seem to be contradicting each other.
First item:
- When inheriting from a class without
__slots__
, the__dict__
attribute
of that class will always be
accessible, so a__slots__
definition in the subclass is
meaningless.
Sixth item:
- The action of a
__slots__
declaration is limited to the class
where it is defined. As a result,
subclasses will have a__dict__
unless they also define__slots__
(which must only contain names of any
additional slots).
It seems to me these items could be better worded or shown through code, but I have been trying to wrap my head around this and am still coming up confused. I do understand how __slots__
are supposed to be used, and I am trying to get a better grasp on how they work.
The Question:
Can someone please explain to me in plain language what the conditions are for inheritance of slots when subclassing?
(Simple code examples would be helpful but not necessary.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
正如其他人提到的,定义 __slots__ 的唯一原因是节省一些内存,当您拥有具有预定义属性集的简单对象并且不希望每个对象都带有字典时。当然,这仅对于您计划拥有许多实例的类才有意义。
节省的费用可能不会立即明显 - 考虑...:
由此看来,有插槽的大小大于无插槽的大小!但这是一个错误,因为
sys.getsizeof
没有考虑“对象内容”,例如字典:由于字典本身就占用 140 字节,显然“32 字节”对象
n 据称并未考虑每个实例中涉及的所有内容。您可以使用第三方扩展(例如 pympler)做得更好:
这可以更清楚地显示内存占用量这是由
__slots__
保存的:对于像本例这样的简单对象,它略小于 200 字节,几乎是对象总体占用空间的 2/3。现在,由于现在对于大多数应用程序来说,多或少兆字节并不那么重要,这也告诉您,如果您只需要几个字节,则 __slots__ 不值得麻烦。一次有数千个实例——然而,对于数百万个实例来说,它确实会产生非常重要的差异。您还可以获得微观的加速(部分是由于使用__slots__
对小对象更好的缓存使用):但这在某种程度上取决于 Python 版本(这些是我使用 2.5 重复测量的数字;使用 2.6,我认为对于设置属性来说,
__slots__
具有更大的相对优势,但对于获取来说,实际上是一个很小的dis优势。 它)。现在,关于继承:对于一个无字典的实例,其继承链上的所有类也必须具有无字典的实例。具有无字典实例的类是那些定义了
__slots__
的类,以及大多数内置类型(实例具有字典的内置类型是您可以在其实例上设置任意属性(例如函数)的类型)。插槽名称的重叠并不被禁止,但它们没有用,而且会浪费一些内存,因为插槽是继承的:如您所见,您可以在
AB
实例上设置属性a
--AB
本身只定义了 slotb
,但它继承了A
的 slota
。重复继承的槽并不是被禁止的:但确实浪费了一点内存:
所以确实没有理由这样做。
As others have mentioned, the sole reason for defining
__slots__
is to save some memory, when you have simple objects with a predefined set of attributes and don't want each to carry around a dictionary. This is meaningful only for classes of which you plan to have many instances, of course.The savings may not be immediately obvious -- consider...:
From this, it would seem the with-slots size is larger than the no-slots size! But that's a mistake, because
sys.getsizeof
doesn't consider "object contents" such as the dictionary:Since the dict alone takes 140 bytes, clearly the "32 bytes" object
n
is alleged to take are not considering all that's involved in each instance. You can do a better job with third-party extensions such as pympler:This shows much more clearly the memory footprint that's saved by
__slots__
: for a simple object such as this case, it's a bit less than 200 bytes, almost 2/3 of the object's overall footprint. Now, since these days a megabyte more or less doesn't really matter all that much to most applications, this also tells you that__slots__
is not worth the bother if you're going to have just a few thousand instances around at a time -- however, for millions of instances, it sure does make a very important difference. You can also get a microscopic speedup (partly due to better cache use for small objects with__slots__
):but this is somewhat dependent on Python version (these are the numbers I measure repeatably with 2.5; with 2.6, I see a larger relative advantage to
__slots__
for setting an attribute, but none at all, indeed a tiny disadvantage, for getting it).Now, regarding inheritance: for an instance to be dict-less, all classes up its inheritance chain must also have dict-less instances. Classes with dict-less instances are those which define
__slots__
, plus most built-in types (built-in types whose instances have dicts are those on whose instances you can set arbitrary attributes, such as functions). Overlaps in slot names are not forbidden, but they're useless and waste some memory, since slots are inherited:as you see, you can set attribute
a
on anAB
instance --AB
itself only defines slotb
, but it inherits slota
fromA
. Repeating the inherited slot isn't forbidden:but does waste a little memory:
so there's really no reason to do it.
第一项
第六项
在不久的将来您可能不需要使用
__slots__
。它只是为了节省内存,但牺牲了一些灵活性。除非你有数以万计的对象,否则这并不重要。First Item
Sixth Item
You probably won't need to use
__slots__
in the near future. It's only intended to save memory at the cost of some flexibility. Unless you have tens of thousands of objects it won't matter.这些项目实际上并不相互矛盾。第一个涉及未实现
__slots__
的类的子类,第二个涉及实现实现__slots__
的类的子类。不实现 __slots__ 的类的子类
我越来越意识到,尽管 Python 文档(正确地)被认为是伟大的,但它们并不完美,特别是对于该语言的较少使用的功能。我将更改 docs 如下:
__slots__
对于这样的类还是有意义的。它记录了类的属性的预期名称。它还为这些属性创建槽 - 它们将获得更快的查找速度并使用更少的空间。它只允许其他属性,这些属性将被分配给__dict__
。此更改已被接受,现在位于最新文档。
下面是一个示例:
Bar
不仅具有其声明的槽,还具有 Foo 的槽 - 其中包括__dict__
:执行 实现的类的子类
__slots__
嗯,这也不完全正确。
__slots__
声明的操作不完全限于定义它的类。例如,它们可能会对多重继承产生影响。我会将其更改为:
我实际上已经将其更新为:
下面是一个示例:
我们看到槽类的子类可以使用槽:(
有关 __slots__ 的更多信息,请在此处查看我的答案。)
Those items don't actually contradict each other. The first regards subclasses of classes that don't implement
__slots__
, the second regards subclasses of classes that do implement__slots__
.Subclasses of classes that don't implement
__slots__
I am increasingly aware that as great as the Python docs are (rightly) reputed to be, they are not perfect, especially regarding the less used features of the language. I would alter the docs as follows:
__slots__
is still meaningful for such a class. It documents the expected names of attributes of the class. It also creates slots for those attributes - they will get the faster lookups and use less space. It just allows for other attributes, which will be assigned to the__dict__
.This change has been accepted and is now in the latest documentation.
Here's an example:
Bar
not only has the slots it declares, it also has Foo's slots - which include__dict__
:Subclasses of classes that do implement
__slots__
Well that's not quite right either. The action of a
__slots__
declaration is not entirely limited to the class where it is defined. They can have implications for multiple inheritance, for example.I would change that to:
I have actually updated it to read:
Here's an example:
And we see that a subclass of a slotted class gets to use the slots:
(For more on
__slots__
, see my answer here.)从您链接的答案中:
“当从没有
__slots__
的类继承时,该类的__dict__
属性将始终是可访问的”,因此添加您自己的__slots__
无法阻止对象拥有__dict__
,并且无法节省空间。关于 __slots__ 不被继承的说法有点迟钝。请记住,它是一个魔法属性,其行为与其他属性不同,然后重新阅读,说这个魔法槽行为不是继承的。 (这就是全部内容了。)
From the answer you linked:
"When inheriting from a class without
__slots__
, the__dict__
attribute of that class will always be accessible", so adding your own__slots__
cannot prevent objects from having a__dict__
, and cannot save space.The bit about
__slots__
not being inherited is a little obtuse. Remember that it's a magic attribute and doesn't behave like other attributes, then re-read that as saying this magic slots behavior isn't inherited. (That's really all there is to it.)我的理解是这样的:
class
X
没有__dict__
<-------->
classX
及其超类都指定了__slots__
在这种情况下,该类的实际插槽由
X
及其超类的__slots__
声明的并集;如果此联合不是不相交的,则行为未定义(并且将成为错误)My understanding is as follows:
class
X
has no__dict__
<------->
classX
and its superclasses all have__slots__
specifiedin this case, the actual slots of the class are comprised from the union of
__slots__
declarations forX
and its superclasses; the behavior is undefined (and will become an error) if this union is not disjoint