【问题标题】:Python class variable overwrites all instance variables when using slots - why?Python 类变量在使用插槽时会覆盖所有实例变量 - 为什么?
【发布时间】:2021-11-10 16:57:52
【问题描述】:

我注意到一些我不完全理解的奇怪行为。出于性能原因,我在课堂上使用 slots。为什么一个简单的类变量赋值就这么容易破坏所有的类实例?

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)

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

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

【问题讨论】:

    标签: python class syntax


    【解决方案1】:

    当您这样做时,您正在破坏__slots__ 的实施:

    Person.name = 'hacked'
    

    来自docs

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

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

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

    【讨论】:

    • 我知道我在滥用它(我不会在普通代码中这样做,这只是一个实验),我只是对解释器允许这样做感到惊讶。如果你想显式定义一个类变量(在类定义中)你会得到一个错误。覆盖插槽变量时,我希望有类似的行为。
    猜你喜欢
    • 2012-05-20
    • 2014-11-29
    • 1970-01-01
    • 2016-05-27
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多