实例属性与类属性访问的区别

3 投票
2 回答
1306 浏览
提问于 2025-04-15 13:44

我有一个Python类

class pytest:
    i = 34
    def func(self):
        return "hello world"

当我访问 pytest.i 时,我得到了34。我还可以用另一种方式做到这一点:

a = pytest()
a.i

这样也会得到34。

如果我尝试访问一个不存在的 pytest.j,我会得到

Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
pytest.j
AttributeError: class pytest has no attribute 'j'

而当我尝试 a.j 时,错误是

Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
a.j
AttributeError: pytest instance has no attribute 'j'

所以我的问题是:这两种情况到底发生了什么,区别是什么呢?

2 个回答

0

简单来说,跟类和对象相关的变量有两种:类变量和实例变量。类变量是和类相关的,而实例变量是和对象相关的。下面是个例子:

class TestClass:
    classVar = 0
    def __init__(self):
        self.instanceVar = 0

classVar是一个类变量,它和TestClass这个类有关。instanceVar是一个实例变量,它和TestClass类型的对象有关。

print(TestClass.classVar) # prints 0
instance1 = TestClass() # creates new instance of TestClass
instance2 = TestClass() # creates another new instance of TestClass

instance1和instance2共享classVar,因为它们都是TestClass类型的对象。

print(instance1.classVar) # prints 0
TestClass.classVar = 1
print(instance1.classVar) # prints 1
print(instance2.classVar) # prints 1

但是,它们各自都有自己的instanceVar的副本,因为实例变量是和每个具体的实例相关的,而不是和类相关的。

print(instance1.instanceVar) # prints 0
print(TestClass.instanceVar) # error! instanceVar is not a class variable
instance1.instanceVar = 1
print(instance1.instanceVar) # prints 1
print(instance2.instanceVar) # prints 0

正如Aaron所说,如果你想访问一个实例变量,Python会先检查这个对象的实例变量,然后再检查这个对象类型的类变量。类变量可以看作是实例变量的默认值。

7

不,这两个是不同的概念。

在Python中,所有东西都是对象。类是对象,函数也是对象,实例也是对象。因为一切都是对象,所以它们的表现方式很相似。在你的例子中,你创建了一个名为“pytest”的类实例(也就是一个类型为“Class”的对象)。这个对象有两个属性:ifuci是“整数”或“数字”的实例,而fuc是“函数”的实例。

当你使用“pytest.j”时,你是在告诉Python:“去查找对象pytest,然后在找到后再查找i。”虽然“pytest”是一个类实例,但这并不重要。

当你创建一个“pytest”的实例(也就是一个类型为“pytest”的对象)时,你就得到了一个有“默认值”的对象。在你的例子中,apytest的一个实例,这意味着任何在a中找不到的东西,接下来都会在pytest中查找。

所以a.j的意思是:“先在a中查找。如果找不到,再去pytest中查找。”但是j并不存在,Python现在需要给你一个有意义的错误信息。它可能会说“类pytest没有属性'j'”。这虽然是正确的,但没有什么实际意义:你得自己搞清楚是通过a去访问j的,这会让人困惑。Guido可不想让你这样。

因此,Python使用了不同的错误信息。因为它并不总是能知道实例的名字(a),设计者决定用类型来代替,所以你会看到“pytest实例...”这样的提示。

撰写回答