您的位置:

Python类属性详解

一、属性介绍

在Python中,类属性是指属于类的公有属性。与实例属性不同,类属性是被类的所有实例共享的属性。类属性存在于定义类之后,实例化之前。

定义类属性需要在类中直接声明,形如:变量名 = 值,且必须在类方法与普通方法之外。

通过类名修改类属性可以使该属性对所有实例生效。对类属性的修改以及随后被不同的实例访问会显示修改后的值。

class MyClass:
    class_attribute = 1
    
    def __init__(self, instance_attribute):
        self.instance_attribute = instance_attribute
    
    def modify_class_attribute(self, value):
        MyClass.class_attribute = value
        
obj1 = MyClass(10)
obj2 = MyClass(20)

print(obj1.class_attribute, obj2.class_attribute)
obj1.modify_class_attribute(2)
print(obj1.class_attribute, obj2.class_attribute)

输出:1 1

2 2

二、属性访问

Python中的属性访问机制是动态的,除了类属性之外,所有的属性都是在运行期间确定的。

当在实例中找不到相应的属性名时,Python会尝试在类中查找该属性名。如果类中也没有找到,会继续在该类的父类中查找,以此类推。

由于Python默认支持“公有”、“私有”、“保护”三种访问级别,Python属性访问还有一个特殊的现象:非公有属性可以通过'_类名__属性名'这种方式进行直接访问。

class MyClass:
    class_attribute = 1
    __non_public_attribute = 2
    
    def __init__(self, instance_attribute):
        self.instance_attribute = instance_attribute

obj = MyClass(10)
print(obj.class_attribute)  # 访问公有属性
print(obj._MyClass__non_public_attribute)  # 访问非公有属性

输出:1 2

三、属性删除

可以使用内置函数del删除实例属性,但不能删除类属性。

这是由于Python的属性访问算法会在类与父类指向完整的属性空间,而类属性实际上存在于该空间中。

同时,对类属性的删除操作仅仅是从该类实例的属性字典中删除了该属性名,而不是真正的删除了该类属性。

class MyClass:
    class_attribute = 1
    
    def __init__(self, instance_attribute):
        self.instance_attribute = instance_attribute

obj = MyClass(10)
print(obj.class_attribute)
# del obj.class_attribute 不能删除类属性
del obj.instance_attribute
print(obj.__dict__)

输出:1

{}

四、属性继承

Python支持多重继承,因此子类可能继承多个基类的属性。

在实例化子类时,Python遵循深度优先搜索原则查找并继承属性。即先检查在当前类中是否存在该属性,若不存在则从父类中继续查找。在多个父类中存在同名属性时,Python会按照类定义时的顺序进行查找。

class Father:
    x = 1
      
class Mother:
    x = 2

class Son(Father, Mother):
    pass

print(Son.x)

输出:1

五、属性覆盖

在继承属性的过程中,若在子类中存在同名属性,子类的属性会覆盖父类的属性。

所以可以通过该特性实现多态。

class Father:
    def func(self):
        print('i am father')
      
class Son(Father):
    def func(self):
        print('i am son')

Father().func()
Son().func()

输出:
i am father
i am son

六、总结

Python的属性机制是动态的,支持三种访问级别:公有、私有和保护。其中对于私有属性可以通过'_类名__属性名'的方式来直接访问;对于类属性,则是被所有实例共享,并且只能在类外部修改(即通过类名修改);对于实例属性,则可以在类内任何方法以及类外部进行修改和删除。最后,Python的属性访问会按照深度优先搜索的原则进行查找,同时支持属性覆盖和多态。