Python 类属性与实例属性

首先我们简要说下类属性与实例属性在概念上的不同之处:
然后我们通过一个具体的例子,来看下在访问类属性和实例属性时,是怎么进行操作的 。
# 定义了类之后,Python就会为类分配一块内存空间,里面放它的相关属性和方法 。# 这里在类中定一个了一个类属性,相当于在Person类的内存空间中有了值为10的age属性 。class Person():age = 10# 给类名加上函数调用符号,就相当于创建了一个对象 。# 现在我们分别创建了一个叫沈腾的人和一个叫马丽的人 。# 创建后,Python也会为对象分别分配内存空间st = Person()ml = Person()# 使用对象访问类属性,它会先去对象的内存空间里面找age属性,如果没有,就向上找对象所属类的内存空间 。# 而在这里它并不是直接取了对象的内存空间的age属性,因为此时对象的内存空间里面还没有age属性 。# 这里实际上是对象访问了类的内存空间,从类内存空间中取出来age属性的值,并打印出来# 所以这里沈腾对象属性值和马丽对象属性值都是类属性值10print("st对象:%s" % st.age)print("ml对象:%s" % ml.age)# 要记住一点,只要给对象有了赋值操作,那么就相当于给对象的内存空间中动态创建了一个属性,所以这里此时沈腾对象的内存空间中有了一个age属性了,是属于这个对象的属性,也就是我们所说的实例属性 。# 那么此时st.age会先在对象内存空间中找age属性,找到了,就不会再去类内存空间中找,所以此时st.age访问的是对象内存空间的age属性 。# 所以此时沈腾对象属性值是沈腾对象内存空间age属性的值,也就是12 。而非类属性值10 。st.age = 12 print("st对象:%s" % st.age)# 因为马丽对象还没有进行赋值操作,所以它还没有在它自己的内存空间中动态创建age属性 。所以它这里访问的依旧是类内存空间中的age属性值 。# 而上述语句改变的是沈腾内存空间中age的值,所以不会影响到马丽对象属性值 。# 这里打印马丽对象属性值也就是类的属性值10 。print("ml对象:%s" % ml.age) # 因为上面的赋值语句改变的是对象的内存空间,所以类属性的值其实并没有改变,依旧是原来的值10 。print("类属性值:%s" % Person.age)
我们看下具体的打印结果和我们分析的是否一致,可以看到,在没有st.age没有执行之前的打印值都是类属性的值10,而st.age=12执行后,st.age值就变成了12,而ml.age和.age都没有变,依旧是类属性的10 。

Python 类属性与实例属性

文章插图
我们再通过图解的形式理解下:
还有一点需要说明,我们可以在类的构造方法中对对象的属性进行初始化,这里也是相当于对对象的属性进行了赋值操作,所以也是在对象的内存空间中动态的创建了实例属性 。因为self参数就相当于对象自己,self.age在对象创建后就相当于对象.age,如st.age,ml.age,和上面例子原理是一样的 。
class Person():age = 10def __init__(self, age):self.age = age# 因为在构造方法中就已经给self.age属性赋值了 。# 所以创建对象时,沈腾对象内存空间中和马丽对象内存空间中就都有了age属性,这是属于对象的属性 。# 所以以后在使用st.age和ml.age时,访问到的都是对象内存空间中的age值了 。st = Person(18)ml = Person(9)# 这里就访问的是对象内存空间中的age属性值了# 所以分别打印18和9print("st对象:%s" % st.age)print("ml对象:%s" % ml.age)# 这里给沈腾对象的age属性重新赋值,改变的也仅是沈腾对象内存空间中的age属性值# 不会改变马丽对象内存空间age属性值和类内存空间age属性值 。st.age = 12print("st对象:%s" % st.age)print("ml对象:%s" % ml.age) print("类属性值:%s" % Person.age)