1

在 python 中谈论类属性时的常见示例如下:

Python 2.7.6 (default, Sep 9 2014, 15:04:36)
>>> class B(object):
... cv = []
...
>>> b1 = B()
>>> b2 = B()
>>> b1.cv, b2.cv, B.cv
([], [], [])
>>> b1.cv.append(1)
>>> b1.cv, b2.cv, B.cv
([1], [1], [1])
>>> b2.cv.append(2)
>>> b1.cv, b2.cv, B.cv
([1, 2], [1, 2], [1, 2])
>>> B.cv.append(3)
>>> b1.cv, b2.cv, B.cv
([1, 2, 3], [1, 2, 3], [1, 2, 3])

它表明类属性在类及其所有实例之间共享。

但是当我们重新分配类属性的值时会发生这种情况,即没有绑定到类属性的初始对象的突变:

>>> class A(object):
... cv = 0
...
>>> a1 = A()
>>> a2 = A()
>>> a1.cv, a2.cv, A.cv
(0, 0, 0)
>>> a1.cv = 1
>>> a1.cv, a2.cv, A.cv
(1, 0, 0)
>>> a2.cv = 2
>>> a1.cv, a2.cv, A.cv
(1, 2, 0)
>>> A.cv = 3
>>> a1.cv, a2.cv, A.cv
(1, 2, 3)

在这里我们可以看到,每次这个类属性存储它的唯一值,并且在实例和类命名空间应用的下一个分配中它不会被覆盖。

为什么会有这样的行为?

我无法理解这种逻辑可能是什么样的逻辑,它会导致“不可变”(A)和“可变”(B)情况下如此“不相关”的行为。这让我想到“没有任何使用感类变量”,因为它们可能容易出错......

我希望在这条隧道里看不到光的人是我……

4

3 回答 3

2

在第一个示例中,您对列表进行了变异。宇宙中只有一个列表实例,B.__dict__['cv']. 在第二个示例中,您分配值。当您这样做时,它们会在每个特定实例中进行分配a(1|2|3),因为这就是属性设置在 Python 中的工作方式(它保存到__dict__您尝试更改属性的任何内容)。您必须进行修改A.cv才能修改所有内容,并且所做的任何更改a(1|2|3)都会覆盖所做的更改。

(Python 尝试使用a(1|2|3).__dict__然后回退到A.__dict__.)

于 2015-03-07T19:29:04.847 回答
1

最后一个例子解释了 Chris Warrick 的答案

>>> A.cv = 0
>>> a1, a2 = A(), A()
>>> A.cv, a1.cv, a2.cv
(0, 0, 0)
>>> A.cv = 1
>>> A.cv, a1.cv, a2.cv
(1, 1, 1)
>>> a1.cv = 2   # Here the new instance attribute is created for a1, 
# and so it will hide the class attribute with the same name, 
# once getting the value from instance namespace
>>> A.cv, a1.cv, a2.cv
(1, 2, 1)
>>> A.cv = 3
>>> A.cv, a1.cv, a2.cv
(3, 2, 3)
于 2015-03-07T19:34:55.047 回答
0

如果您不打算通过实例使用类属性,则可以有效地使用它们。例如,我喜欢在类属性中管理同一类的一组对象。如果你听说过 Pygame,那是我最常使用这种技术的地方。

class Alien:
    sprites = []

    def __init__(self, x, y):
        self.surf = pygame.image.load('Alien.png')
        self.rect = self.surf.get_rect()

        self.rect.topleft = (x, y)
        Alien.sprites.append(self)

    @staticmethod
    def draw_sprites(screen):
        for sprite in Alien.sprites:
            screen.blit(sprite.surf, sprite.rect)

您是否看到使用类方法和属性可以如此轻松地进行对象管理?

于 2015-03-08T00:29:31.047 回答