参考教程:【Python】零基础入门——面向对象编程(强烈推荐)_哔哩哔哩_bilibili
前言看到这个标题,我觉得大部分人是奇怪的,因为在我之前的想法中,我一直觉得类是模板,是不占内存的,但在接触了python以后,我觉得类其实也是一个对象,它也是占了内存的。
顺便提一句,在python中,类名是可以直接调用属性,例如:
class Student: pass print(Student.__name__)
类名与类之间的关系
而且跟之前学C++一样,函数名是一个指针,也就是函数的地址,所以类名其实也是一个指针,或者叫做地址ID号,所以我们看到类与类名的关系可以看成如下的关系:
对象属性/对象与类的基本内存关系
而在python中,对象里面其实存在了一个名为class的属性指向了对象本身,图示如下:
有意思的是python面向对象中对象的属性,首先在python当中,对象的属性是可以后期加的,例如如下这种情况:
class Student: pass ZhangSan = Student() ZhangSan.age = 18 # 查看对象里面的所有属性 print(ZhangSan.__dict__) # 同时也可以删除属性 del p.age # 修改看起来没有啥区别,只需要直接修改即可,但内存 *** 作也还是很有意思,而且如果属性已经存在了才叫修改,不然该 *** 作就表示为添加属性 print(id(ZhangSan.age)) ZhangSan.age = 21 print(id(ZhangSan.age)) # 这里会发现这里的ID号是不一样的 # 但值得注意的是列表修改是不会存在修改内存的地址的,也就是如下两个ID号并没有发生改变,以下名字都是乱取的,如有雷同,还请见谅 ZhangSan.Former_girlfriend["吴琴","徐四"] ZhangSan.Former_girlfriend["吴琴","徐四","冯安康"]
而更有意思的是python对象添加属性的内存的 *** 作,它并不是将属性直接添加到自己的内存里面,而是另外再开一片内存,用来存这个属性值,然后保存好这个属性值的ID号(地址),图示如下:
对象属性修改的内存图示如下,python不会直接修改原内存的值,而是直接再开一块内存,将对象内属性对应的地址(ID号)进行修改,(其中18没有其他引用情况下,会被释放掉)图示如下:
对象属性被删除时的内存 *** 作图示如下(18的内存是否释放,主要看有没有其他变量引用它,没有会一起释放掉):
对象内存里面一些好玩的东西
首先第一个好玩的东西就是,从上面我们可以知道我们是可以后天增加属性的,但是对象1增加了一个属性,不代表对象2也增加一个这个属性,如果强行去访问就会报错,例如:
class student: pass ZhangSan = student() ZhangSan.age = 18 LiSi = student() LiSi.name = "LiSi" # 在这里之前都没错,但如果我访问张三的name就会出错了,因为我并没有给张三加上name的属性,所以就会报错
类属性的内存关系
由于篇幅问题,这里我仅介绍类与对象属性之间的不同,与我之前学其他语言不同,python的类也可以看作为一个对象,所以类的属性也是可以直接使用的
类属性跟对象一样都是用ID号(指针)的方式存储在类存储里,其中值得关注的点就是对象也可以访问类属性,例如:
class Student: age = 18 grade = 'A' pass ZhangSan = Student() print(ZhangSan.age)
这里乍一看跟其他对象的访问都没有问题,但如果说你要修改它的值,这里就存在说法啦,而且反映到内存里面,对象首先通过__class来访问到类,然后再通过类来访问类属性值,而不是把这三个属性放到对象的内存里面或则和重开一块内存,也就是说多个对象一开始访问到的都是类属性的值,不是各自对象的值关系图如下所示:
python对象的属性查找机制
通过上面的例子,就不得不说python对象的属性访问顺序了,一般来说对象的属性会首先从自身开始找起,如果自身没有,则会从类里面开始找,如果类里面还没有,会从父类里面开始找,一直找到最后发现没有,就会报错,即这个属性不存在。这里通过下面的例子就可以发现(但注意不可以通过对象来进行增加和修改,同理删除也是)
class Student: age = 18 grade = 'A' pass class person: sex = 'man' pass ZhangSan = Student() ZhangSan.__class__ = person # 则这里访问age就会报错 print(ZhangSan.age) #这里会成功打印出来 print(ZhangSan.sex) # 这里也可以通过删除报错来验证 class Student: age = 18 grade = 'A' pass ZhangSan = Student() # 这里会报一个错误,会发现,类在这里是一个对象 del Student.age print(Student.age) # 这里会报一个对象没有age的错误 del ZhangSan.age
python对象属性与类属性相同时会增加内存
这个时候你一定会问了,如果我有多个对象,都访问这个属性,是不是都访问到类属性里面?那我可以准确地告诉您,如果你没有修改过这个值,答案是:是的
但如果你修改这个属性值,那么对象会重新开一块内存,图示如下:
类属性中的dict和对象中的dict
与之前的说法进行一点点小小的修改,在python当中其实是存在一个dict属性的,所以其实对象或者类的属性其实是保存在一个叫做dict属性的键值对里面,然后与对象不同的是类的dict属性是只能读不能写的,在如下的例子可以验证
class Student: age = 18 grade = 'A' pass ZhangSan = Student() print(ZhangSan.__dict__) # 或者如下方式 ZhangSan.__dict__ = {"name": "ZhangSan","age": 21} print(ZhangSan.__dict__) # 或者 ZhangSan.age = 21 print(ZhangSan.__dict__)
思考
看到上面那一部分,那么下面这个程序输出的值就不言而喻了,答案分别是:
class Student: age = 18 grade = 'A' pass ZhangSan = Student() ZhangSan.age += 3 # ZhangSan.age = ZhangSan.age + # 输出 21 print(ZhangSan.age) # 输出 18 print(Student.age)
怎么限制python对象不可以随意增加属性
# 可以加关键字__slot__ 用于限制添加属性 class Student: age = 18 grade = 'A' __slot__ = ["age","grade"] pass # 这样就限制只能添加age grade这两个属性
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)