首页 > 解决方案 > 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)

因此,所有实例的“名称”属性都会被覆盖。解释器不应该阻止它吗?当您想要显式定义与插槽中使用的同名的类变量时,就会出现这种情况。

我有点困惑,因为它看起来太容易受到意外损坏。

标签: pythonclasssyntax

解决方案


您在执行以下__slots__操作时会中断执行:

Person.name = 'hacked'

文档

__slots__通过为每个变量名创建描述符(实现描述符)在类级别实现。因此,类属性不能用于设置由__slots__;定义的实例变量的默认值。否则,类属性将覆盖描述符分配。

这意味着Person.name实际上<class 'member_descriptor'>是创建类的时间。在你的'hack'之后,它变成了一个正常的str. type(Person.name)您可以通过在“hack”之前和之后打印来检查这一点。

__slots__以微妙的方式改变类行为,所以在使用它之前仔细阅读文档。


推荐阅读