今天我偶然发现了以下行为:
\nclass myobject(object):\n """Should behave the same as object, right?"""\n\nobj = myobject()\nobj.a = 2 # <- works\nobj = object()\nobj.a = 2 # AttributeError: \'object\' object has no attribute \'a\'\nRun Code Online (Sandbox Code Playgroud)\n我想知道设计这种语言背后的逻辑是什么,因为这对我来说完全是自相矛盾的。它打破了我的直觉,如果我创建一个子类,不加修改,它的行为应该与父类相同。
\n编辑:很多答案表明这是因为我们希望能够编写可以使用的类,__slots__而不是__dict__出于性能原因。然而,我们可以这样做:
class myobject_with_slots(myobject):\n __slots__ = ("x",)\n \nobj = myobject_with_slots()\nobj.x = 2\nobj.a = 2\nassert "a" in obj.__dict__ # \xe2\x9c\x94\nassert "x" not in obj.__dict__ # \xe2\x9c\x94\nRun Code Online (Sandbox Code Playgroud)\n所以看起来我们可以同时拥有两者,那么为什么不允许__slots__两者同时存在,但一对一的子类却允许呢?__dict__object
考虑这段代码:
class A:
__slots__ = ()
class B(A):
__slots__ = ("x", "y")
b = B()
b.z = 1 # AttributeError
Run Code Online (Sandbox Code Playgroud)
__slots__ = ("x", "y")意味着B实例没有 a__dict__并且只能有属性x和y。这对性能有好处。
如果删除__slots__from A,则A实例将获得 a __dict__,这意味着它们的子类也会获得 a ,特别是B。__slots__这降低了提高性能的有效性。
因为object是所有类的超类,所以你可以像这里一样考虑它A,拥有__slots__ = ()和没有__dict__,这样其他类也可以避免拥有 a__dict__并充分受益于 custom __slots__。
因为派生类不一定支持setattr其中任何一个。
class myobject(object):\n """Should behave the same as object!"""\n __slots__ = ()\n\nobj = myobject()\nobj.a = 2 # <- works the same as for object\nRun Code Online (Sandbox Code Playgroud)\n由于所有类型都派生自object,因此大多数内置类型(例如 )list也是示例。
object子类可能支持任意属性分配,但并非所有子类都支持。因此,公共基类也不支持这一点。
对任意属性的支持通常由所谓的__dict__槽支持。这是一个固定属性,包含文字dict 1来存储任何属性-值对。
事实上,我们可以手动定义__dict__槽来获得任意属性支持。
class myobject(object):\n """Should behave the same as object, right?"""\n __slots__ = ("__dict__",)\n\nobj = myobject()\nobj.a = 2 # <- works!\nprint(obj.__dict__) # {\'a\': 2}\nRun Code Online (Sandbox Code Playgroud)\n这个演示的要点是固定属性实际上是 Python 的“基本行为”;当需要时,任意属性支持构建在顶部。
\n默认情况下为子类型添加任意属性object可提供更简单的编程体验。但是,仍然支持object子类型的固定属性可以实现更好的内存使用和性能。
\n\n数据模型:
\n__slots__\n
__slots__过度使用所节省的空间__dict__可能是巨大的。属性查找速度也可以显着提高。
请注意,可以定义具有固定属性和任意属性的类。固定属性将受益于改进的内存布局和性能;由于它们不存储在 中__dict__,因此其内存开销2较低 \xe2\x80\x93 但仍然有成本。
1 Python 实现可以使用不同的优化类型,只要__dict__它们的行为类似于dict.
2为了使基于散列的查找高效工作且很少发生冲突,adict必须大于其存储的项目数。
| 归档时间: |
|
| 查看次数: |
468 次 |
| 最近记录: |