静态类变量和Python中的`self`

时间:2014-03-27 19:44:31

标签: python class oop static self

为什么下面的例子表现不同?

示例1:foo似乎表现为特定于各种对象的类变量

class A: 
    foo = 1
a, b = A(), A()
a.foo = 5
print b.foo
----------------
Output: 1

示例2:foo似乎表现得像一个对所有对象都相同的静态类变量。也许这种行为与作为指针的列表有关。

class A: 
    foo = []
a, b = A(), A()
a.foo.append(5)
print b.foo
----------------
Output: [5]

示例3:没有工作

class A: 
    self.foo = []
a, b = A(), A()
a.foo.append(5)
print b.foo
----------------
Output: Error

3 个答案:

答案 0 :(得分:6)

前两个示例都是类属性。他们看起来不同的原因是因为你在两种情况下都没有做同样的事情:你在第一种情况下分配一个新值,在第二种情况下修改现有值。

请注意,您在前两个示例中没有做同样的事情。在第一个示例中,您执行a.foo = 5,分配新值。在第二个例子中,如果你做了类似的事情,分配a.foo = [5],你会看到与第一个例子中相同的结果。但相反,您使用a.foo.append(5)更改了现有列表,因此行为不同。 a.foo = 5仅更改变量(即,它指向的值); a.foo.append(5)更改本身。

(请注意,没有办法在第一个例子中做第二个例子。也就是说,没有像a.foo.add(1)那样添加1到5个。那是因为整数不是可变的,但是列表是。​​但重要的不是列表"是可变的,而是你突变了一个。换句话说,它不重要你可以使用列表,在特定代码中实际执行的操作非常重要。)

另请注意,虽然您在类定义中定义的foo是类属性,但在执行a.foo = 5时,您正在实例上创建新属性 。它碰巧与class属性具有相同的名称,但它并没有更改class属性的值,这是b.foo仍然可以看到的值。

最后一个例子不起作用,因为就像在前两个例子中一样,class块内的代码在类范围内。没有self,因为在定义类时还没有实例。

StackOverflow上有很多很多关于此的问题,我恳请您搜索并阅读其中的一些问题,以便更全面地了解其工作原理。

答案 1 :(得分:1)

这不起作用:

class A: 
    self.foo = []

这会引发错误。

NameError: name 'self' is not defined

因为self不是Python中的关键字,所以它只是一个变量名,通常分配给在调用类时传递给类方法的类实例。

以下是一个例子:

class A(object): 
    def __init__(self):
        self.foo = []

a, b = A(), A()
a.foo.append(5)
print(b.foo)

然后返回:

[]

当每个人都被初始化时,他们每个人都有自己的列表,可以通过属性foo访问,当一个被修改时,另一个是存储在内存中不同位置的单独列表,没有受到影响。

答案 2 :(得分:1)

差异与可变性/不变性无关,而是执行了哪些操作。

在示例1中,该类具有属性foo。创建对象后,为对象提供另一个属性foo,该属性隐藏前一个属性。因此class属性充当一种“默认”或“后备”。

在示例2中,您有一个对象可以执行操作(当然,它只适用于可变对象)。因此,A.foo引用的对象(由于缺少具有相同名称的实例属性而可以通过a.foob.foo访问)会添加{{1} }。

示例3不起作用,因为在您使用它的地方不存在5

请注意,示例1也适用于可变对象,例如list:

self

此处class A: foo = [] a, b = A(), A() a.foo = [] a.foo.append(5) b.foo.append(10) print a.foo # [5] print b.foo # [10] print A.foo # [10] 获取一个新的空列表。缺少实例属性的a.foo继续引用class属性。所以我们有两个相互独立的空列表,正如我们在b.foo时看到的那样。