鱼C论坛

 找回密码
 立即注册
查看: 1675|回复: 4

[已解决]为什么继承有__slots__属性的父类时,子类的实例化对象的属性会出现缺失

[复制链接]
发表于 2023-8-29 08:31:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
class D:
    __slots__ = ["x", "y"]
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

        
class E(D):
    pass

e = E(10, 15, 20)
e.__dict__
{'z': 20}

这里类E继承有__slots__属性的父类D时,子类E的实例化对象e的属性出现缺失
只有z, x和y消失了
最佳答案
2023-8-29 08:32:25
在Python中,当一个类定义了 __slots__ 属性时,它限制了该类的实例只能具有 __slots__ 中列出的属性。这意味着,实例只能拥有 __slots__ 中指定的属性,而不能拥有其他属性。

在给定的代码中,父类D定义了 __slots__ 属性,包含了"x"和"y"两个属性。当子类E继承了父类D时,子类E的实例化对象e继承了父类D的 __slots__ 属性,并且只能具有"x"和"y"这两个属性。因此,当我们创建子类E的实例化对象e时,只有"x"和"y"这两个属性会被保留在实例的 __dict__ 属性中,而"z"这个属性并不在 __slots__ 中,所以它被忽略了。

这是 __slots__ 属性的一个特性,它可以用来限制实例的属性,从而减少内存消耗和提高访问速度。但需要注意的是,使用 __slots__ 属性时需要谨慎,因为它会限制实例的属性数量,并且只能在类的定义中使用,不能在实例化对象中动态添加新的属性。

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-8-29 08:32:15 | 显示全部楼层
在Python中,使用__slots__属性可以限制类的实例对象只能具有特定的属性。当一个类定义了__slots__属性时,它告诉解释器该类的实例对象只能拥有__slots__属性中列出的属性,而不能拥有其他任意属性。

在你提供的示例代码中,父类D定义了__slots__ = ["x", "y"],这意味着D类的实例对象只能具有"x"和"y"这两个属性。然后,子类E继承了父类D但没有定义自己的__slots__属性。

当你创建子类E的实例对象e时,由于E类继承了D类的__slots__属性,解释器会按照__slots__属性中声明的属性名来分配内存空间。因此,e对象只能拥有"x"和"y"这两个属性,而无法直接访问或设置其他属性,如"z"。

所以,在你的示例中,当你创建了一个子类E的实例对象e,它只能拥有"x"和"y"这两个属性,而"z"属性只是传递给构造函数的参数,并不被保存在e对象中。这就解释了为什么e.__dict__的结果只包含"z"属性,而不包含"x"和"y"属性。

如果你想在子类E中拥有额外的属性,你可以在E类中定义它们的__slots__属性或将其声明为普通属性,这样就可以在实例化对象时进行设置。例如:
class E(D):
    __slots__ = ["z"]
    
    def __init__(self, x, y, z):
        super().__init__(x, y)
        self.z = z
        
e = E(10, 15, 20)
print(e.__dict__)  # {'z': 20, 'x': 10, 'y': 15}

在这个示例中,子类E定义了自己的__slots__属性,并将"z"包括在内。然后在子类E的构造函数中,我们调用了父类D的构造函数并设置了"x"和"y"属性。接着,我们在子类E的构造函数中添加了设置"z"属性的代码。现在,创建子类E的实例对象e时,它将同时拥有"x"、"y"和"z"这三个属性。

希望这解答了你的疑问!如果还有其他问题,请随时提问。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-29 08:32:25 | 显示全部楼层    本楼为最佳答案   
在Python中,当一个类定义了 __slots__ 属性时,它限制了该类的实例只能具有 __slots__ 中列出的属性。这意味着,实例只能拥有 __slots__ 中指定的属性,而不能拥有其他属性。

在给定的代码中,父类D定义了 __slots__ 属性,包含了"x"和"y"两个属性。当子类E继承了父类D时,子类E的实例化对象e继承了父类D的 __slots__ 属性,并且只能具有"x"和"y"这两个属性。因此,当我们创建子类E的实例化对象e时,只有"x"和"y"这两个属性会被保留在实例的 __dict__ 属性中,而"z"这个属性并不在 __slots__ 中,所以它被忽略了。

这是 __slots__ 属性的一个特性,它可以用来限制实例的属性,从而减少内存消耗和提高访问速度。但需要注意的是,使用 __slots__ 属性时需要谨慎,因为它会限制实例的属性数量,并且只能在类的定义中使用,不能在实例化对象中动态添加新的属性。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-29 09:30:01 | 显示全部楼层
本帖最后由 isdkz 于 2023-8-29 09:52 编辑

>>> D.__dict__
mappingproxy({'__module__': '__main__', '__slots__': ['x', 'y'], '__init__': <function D.__init__ at 0x000002172D4D5630>, 'x': <member 'x' of 'D' objects>, 'y': <member 'y' of 'D' objects>, '__doc__': None})
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__weakref__': <attribute '__weakref__' of 'E' objects>, '__doc__': None})

x 和 y 都被 E 的父类的两个成员接管了,所以它不属于 e 对象独有的,自然就在 __dict__ 中看不到了

举个例子:
>>> class T:
...     x = 1
...     y = 1
...     z = 1
...
>>> t = T()
>>> t.__dict__   # t 从它的类中获得的 x, y, z 并不属于它,所以 __dict__ 看不到
{}
>>> t.x = 18  # 当 t 拥有了自己独有的成员对象, __dict__ 就可以看到
>>> t.__dict__
{'x': 18}
>>>

你之前的例子是因为从父类中继承过来的'x': <member 'x' of 'D' objects>, 'y': <member 'y' of 'D' objects>是一个独特的对象,当你给这个属性赋值的时候就会被这个成员对象拦截,所以子类是不可能拥有自己的x,y属性了,因为都被抢走了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2023-8-29 09:49:31 | 显示全部楼层
isdkz 发表于 2023-8-29 09:30
>>> D.__dict__
mappingproxy({'__module__': '__main__', '__slots__': ['x', 'y'], '__init__': , 'x':  ...

明白了,谢谢啦
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-24 20:55

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表