python - Python 类变量在使用插槽时会覆盖所有实例变量 - 为什么?
问题描述
我注意到一些我不完全理解的奇怪行为。出于性能原因,我在课堂上使用插槽。为什么一个简单的类变量赋值就这么容易破坏所有的类实例?
class Person:
__slots__ = ('name',)
def __init__(self, name) -> None:
self.name = name
def __repr__(self):
return self.name
p1 = Person('mc')
p2 = Person('pp')
# The nasty thing here:
Person.name = 'hacked'
print(p1)
print(p2)
因此,所有实例的“名称”属性都会被覆盖。解释器不应该阻止它吗?当您想要显式定义与插槽中使用的同名的类变量时,就会出现这种情况。
我有点困惑,因为它看起来太容易受到意外损坏。
解决方案
您在执行以下__slots__
操作时会中断执行:
Person.name = 'hacked'
从文档:
__slots__
通过为每个变量名创建描述符(实现描述符)在类级别实现。因此,类属性不能用于设置由__slots__
;定义的实例变量的默认值。否则,类属性将覆盖描述符分配。
这意味着Person.name
实际上<class 'member_descriptor'>
是创建类的时间。在你的'hack'之后,它变成了一个正常的str
. type(Person.name)
您可以通过在“hack”之前和之后打印来检查这一点。
__slots__
以微妙的方式改变类行为,所以在使用它之前仔细阅读文档。
推荐阅读
- c++ - Qt keyPressEvent 处理程序仅在按下 ctrl、alt 或 shift 键时作出反应
- java - 我的 ConstraintLayout 没有出现在我的蓝图中
- javascript - Heroku:端口上已经有东西在运行
- multithreading - “全内存屏障”的反面是什么?
- reactjs - “setAllValues”是否只适用于表单的一层嵌套?(默认情况下在 React-form 中)
- python-3.x - 除了使用命令提示符时,atom 不会打开
- artificial-intelligence - 广度优先搜索
- c++ - 虚拟继承:没有匹配的调用函数
- typescript - 如何在不安装 NPM 包的情况下在 TypeScript 2 中进行声明合并?
- python - python:数据在采样到一个小数据集后添加了一个额外的列