这是机器未来的第8篇文章
写在前面:
- 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!
- 专栏简介:本专栏的核心就是:快!快!快!2周快速拿下Python,具备项目开发能力,为机器学习和深度学习做准备。
- 面向人群:零基础编程爱好者
- 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待
- Python零基础快速入门系列
- 快速入门Python数据科学系列
- 人工智能开发环境搭建系列
- 机器学习系列
- 物体检测快速入门系列
- 自动驾驶物体检测系列
- …
@toc
Python中的一切都是对象,变量是对象的引用!对象存于堆中,变量存于栈中。
堆栈都存在与内存中,在运行时分配的内存空间。对象存于堆中,变量存于栈中, 堆区存变量值, 栈区存变量名。栈区存放变量名和其变量值的内存地址, 通过这个内存地址, 变量名可以找到变量值。
直接引用常见于整数类型和字符串类型、元组,修改它们的值,其实已经指向了其它的对象。直接引用的数据类型也被称为不可变数据类型, *不可变数据类型在内存中存储的值仅存储一份,后续定义的变量如果值相等都指向用一个对象,即 x1 is x2 and x1 == x2为True*.
变量名(变量值的地址)存于内存栈区,变量值存于堆区, 变量名直接关联变量值。
x = 10
y = 20
print(hex(id(x)), hex(id(y)))
0x7ff97c90f020 0x7ff97c90f160 # 从输出中可知,x,y指向两个不一样的对象
当执行x = y 时,你会发现x已经指向了一个新的对象,和原来的对象链路已经断开了。
x = 10
y = 20
print(hex(id(x)), hex(id(y)))
x = y
print(hex(id(x)), hex(id(y)))
0x7ff97c90f020 0x7ff97c90f160
0x7ff97c90f160 0x7ff97c90f160 # 从输出中可知,x,y已经指向了同一个对象
注意:字符串的内容是不可以更改的,修改会直接报错!!!
name = "David"
name[2] = 'a'
TypeError Traceback (most recent call last)
C:\Users\ZHOUSH~1\AppData\Local\Temp/ipykernel_9084/4053774855.py in
1 name = “David”2 name[2] = ‘a’
TypeError: ‘str’ object does not support item assignment
间接引用出现在容器类型里,如列表、字典等。
定义列表变量l,其存储结构如图:变量l存储于栈区,变量l通过存储在堆区中列表对象内存地址访问列表对象,然后列表对象再通过其列表中存储的元素地址访问具体的变量值’a’ 和 ‘b’。
l = ['a', 'b']
如果修改变量l[1]的值,例如l[1] = ‘c’,则列表的存储地址不会发生变化,但是列表对象第0个元素的地址会发生变化,其为字符’c’的内存地址,并指向字符对象’c’,但是整个过程变量l的地址不会发生变化.
特别注意:间接引用变量既是值相等,这两个变量也不一定是同一个变量;而对于不可变数据类型,只要值相等,那么这两个变量一定是同一个变量.
x1 = [1, 2, 3, 4, 5, 3, 6, 7]
x2 = [1, 2, 3, 4, 5, 3, 6, 7]
x1 is x2
print(hex(id(x1)), hex(id(x2)))
0x2913b25ab08 0x2913cdf35c8
其实就是对象的引用(别名)
l1 = [1, 'abc', [2, 3]]
l2 = l1
print(id(l1), id(l2))
2822815412936 2822815412936
l2直接指向l1引用的对象,l1和l2的内存地址是一样的, 存储结构如图.
拷贝父对象,不会拷贝对象的内部的子对象。
import copy
l1 = [1, 'abc', [2, 3]]
l2 = copy.copy(l1)
print(id(l1), id(l2))
print('l1:', id(l1[0]), id(l1[1]), id(l1[2]))
print('l2:', id(l2[0]), id(l2[1]), id(l2[2]))
2822786373512 2822786371656 # l1和l2的内存地址不一样,是两个不一样的变量
l1: 140709513457408 2822710032120 2822785142088
l2: 140709513457408 2822710032120 2822785142088 # l1和l2的元素的内存地址是一样的, 包括元素中的列表变量(是直接指向过去的), 验证了仅拷贝父对象的描述.
copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
import copy
l1 = [1, 'abc', [2, 3]]
l2 = copy.deepcopy(l1)
print(id(l1), id(l2))
print('l1:', id(l1[0]), id(l1[1]), id(l1[2]), id(l1[2][0]), id(l1[2][1]))
print('l2:', id(l2[0]), id(l2[1]), id(l2[2]), id(l2[2][0]), id(l2[2][1]))
2822786372360 2822815414472 # l1和l2的内存地址不一样,是不同的变量
l1: 140709513457408 2822710032120 2822786363528 140709513457440 140709513457472
l2: 140709513457408 2822710032120 2822786366024 140709513457440 140709513457472
l2对l1进行了深拷贝,直至数据类型为不可变类型为止.
从输出中可以看到:
思考题:你知道为什么Python在内存中最多只有一个666吗?
《Python零基础快速入门系列》快速导航:
推荐阅读: