对象和对象之间,通过内存的操作存在各种各样的关系,那么这些关系都有什么样的特点又
是怎么分配的呢?
这里就要说到对象的内存分配,对象的引用赋值、对象的深浅拷贝了
3.1.对象的内存分配
对象的创建,依赖于申请的内存空间中数据的加载,对象在内存中的创建过程依赖于三部分
内存处理:对象分配内存地址、引用变量分配内存地址、对象和引用变量之间的关联
参考代码:
# coding=utf-8
from memory_profiler import profile
class Person():
'''自定义类型'''
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
@profile(precision=10)
def main():
'''入口函数'''
p = Person("tom", 18, "男")
print(p)
p2 = Person("tom", 18, "男")
print(p)
if __name__ == "__main__":
# 运行代码
main()
执行结果为:
D:\python36\python.exe C:/Users/leeking/PycharmProjects/python/内存分析/demo06.py
<__main__.Person object at 0x0000001771FE7A58>
<__main__.Person object at 0x0000001771FE7A58>
Filename: C:/Users/leeking/PycharmProjects/python/内存分析/demo06.py
Line # Mem usage Increment Line Contents
================================================
14 15.8281250000 MiB 15.8281250000 MiB @profile(precision=10)
15 def main():
16 '''入口函数'''
17 15.8320312500 MiB 0.0039062500 MiB p = Person("tom", 18, "男")
18 15.8359375000 MiB 0.0039062500 MiB print(p)
19 15.8359375000 MiB 0.0000000000 MiB p2 = Person("tom", 18, "男")
20 15.8359375000 MiB 0.0000000000 MiB print(p)
内存分配图解:
由于对象的创建,是将堆内存中创建的对象的地址临时存储在栈内存中的变量中,那么在程
序中如果要在多个地方使用一个对象数据时应该怎么办呢?一般想到的都是将对象像文件
一样复制一份不就好了。
PYTHON 中对于这样的情况,有三种不同的操作方式
⚫ 如果程序中多个不同的地方都要使用同一个对象,通过对象的引用赋值,将同一个对象
赋值给多个变量
⚫ 如果程序中多个不同的地方都要使用相同的对象数据,通过对象的拷贝完成数据的简单
复制即可,对象中的包含的数据要求必须统一
⚫ 如果程序中多个不同的地方使用相同的而且独立的对象数据,通过对象的深层次的复制
将对象的数据完整复制成独立的另一份即可
3.2. 对象的引用赋值
对象的引用赋值,可以将对象的内存地址同时赋值给多个变量,这多个变量中存放的都是同
一个对象的引用地址,如果通过一个变量修改了对象内容,那么其他变量指向的对象内容也
会同步发生改变.
例如:
在上面,我们定义了一个列表和一个变量,并把变量a指向这个列表的内存地址,之后通过赋值,把a的值赋给b,即将这个内存地址也赋值给b.此时a与b所指向的内存地址一样.所以a与b的值也都相同.我们通过改变a的值,可以发现b的值也跟着发生了变化.
对象的引用变量的赋值,并不是对象的复制或者备份,而仅仅是将对象的地址存储在多个变
量中方便程序操作。
可以看出,我们通过引用赋值操作一个自定义类型,也能起到上面的作用
注意:PYTHON 中所谓对象的引用赋值,针对的是可变类型,不论是组合数据类型或者自定
义 class 类型,都具备引用赋值的操作;但是不适合不可变类型,不可变类型的引用赋值
操作有只读不写的特征,一旦通过变量重新赋值就会重新指向新的引用对象
上面的代码操作不可变数据类型时,应为不可变数据类型的特点,所以在改变a的值时,a会重新指向一个内存地址,所以这个时候的b的值不会发生改变
3.3. 对象的浅拷贝
对于程序中对象的拷贝操作,除了前面介绍的引用赋值操作可以完成同一个对象在程序不
同位置的操作,这里的浅拷贝更是一种对象的临时备份,浅拷贝的核心机制主要是赋值对象
内部数据的引用
PYTHON 内建标准模块 copy 提供了一个 copy 函数可以完成
在上面我们可以看出,通过a浅拷贝出的b,两者的内存地址是不同的.所以浅拷贝就是重新复制了一份a中的值,但是,浅拷贝复制的列表中的值所指向的静态区内存地址是相同的.即id(a[4])与id(b[4])的内存地址是相同的,所以操作a[4]中的数据,那么b[4]中的数据也会发生变化
4.5.对象的深拷贝
和对象的浅拷贝不同,对象的深拷贝,是对象数据的直接拷贝,而不是简单的引用拷贝
主要是通过 PYTHON 内建标准模块 copy 提供的 deepcopy 函数可以完成对象深拷贝
深拷贝则是将所有与的数据都重新复制一份,所以这个时候的id(a[4])与id(b[4])的值不同,即内存地址不同,所以修改a[4]的值,就不会影响b中的值