在 Python 中,类变量通常通过类名点号(.
)加上变量名来访问,例如:c.x
。然而,有趣的是,类实例也可以直接访问类变量,而无需使用类名点号前缀。例如:
class c:
x = 0
>>> c.x
0
>>> c().x
0
上面的代码中,我们定义了一个名为 c
的类,并为其添加了一个类变量 x
,然后分别通过类名和类实例访问了类变量的值,结果都是 0。
这种现象可能会让初学者感到困惑,为什么类变量在类实例中也可以直接访问,而不需要使用 __class__
前缀?它在什么时候会被用到呢?
2、解决方案
2.1、类变量的访问机制
要解答上述问题,首先需要理解 Python 中类变量的访问机制。在 Python 中,类变量是存储在类对象中的,而类实例是通过调用类对象创建的。当我们直接通过类实例访问类变量时,Python 解释器会先在类实例中查找,如果没有找到,再到类对象中查找。这种机制称为属性查找(attribute lookup)。
2.2、使用类名点号前缀访问类变量
如果我们使用类名点号前缀来访问类变量,例如:c.x
,Python 解释器会直接到类对象中查找,而不会去类实例中查找。这是因为类名点号前缀明确指示 Python 解释器到类对象中查找变量。
2.3、使用类实例直接访问类变量
当我们直接通过类实例访问类变量时,例如:c().x
,Python 解释器会先在类实例中查找。如果没有找到,再到类对象中查找。这是因为 Python 解释器会将类实例视为一个特殊的字典,其中存储着类变量和实例变量。
在某些情况下,直接通过类实例访问类变量非常有用。例如,当我们希望修改类变量的值时,可以通过类实例直接修改,而不需要使用类名点号前缀。
>>> c.x += 1
>>> c.x
1
>>> c().x += 1
>>> c.x
1
>>> c().__class__.x += 1
>>> c.x
2
上面的代码中,我们通过类实例修改了类变量 x
的值,并通过使用 c.x
和 c().__class__.x
确认了类变量的值确实被修改了。
2.4、使用场景
直接通过类实例访问类变量的常见场景包括:
- 修改类变量的值
- 获取类变量的值
- 判断类变量是否存在
代码例子
# 定义一个类
class Person:
# 类变量
species = "Homo sapiens"
def __init__(self, name, age):
# 实例变量
self.name = name
self.age = age
# 创建一个类实例
person1 = Person("John", 30)
# 直接通过类实例访问类变量
print(person1.species) # Homo sapiens
# 修改类变量的值
person1.species = "Homo neanderthalensis"
# 再次直接通过类实例访问类变量
print(person1.species) # Homo neanderthalensis
# 获取类变量的值
print(Person.species) # Homo neanderthalensis
# 判断类变量是否存在
print("species" in person1.__dict__) # True
在上面的代码中,我们定义了一个 Person
类,并为其添加了一个类变量 species
和一个实例变量 name
和 age
。然后,我们创建了一个类实例 person1
,并直接通过类实例访问、修改和获取类变量 species
。最后,我们判断了类变量 species
是否存在。