文章插图
您可以看到内存布局与之前的C布局截然不同 。在这里,新创建的Python对象拥有值2337所在的内存,而不是x拥有值2337所在的内存 。Python名称x不直接拥有任何内存地址,不像C变量在内存中拥有静态插槽 。
如果您尝试为x赋新的值,可以尝试以下操作:
文章插图
这里发生的事情与C的同样操作不同,但与Python中的原始绑定没有太大区别 。
这行代码:
· 创建一个新的 PyObject
· 将PyObject的typecode设置为整数
· 将PyObject的值设置为2338
· 将x指向新的PyObject
· 将新的PyObject引用计数增加1
· 将旧的PyObject引用计数减少1
现在在内存中,它看起来像这样:
文章插图
此图有助于说明x指向对象的引用,并不像以前那样拥有内存空间 。它还表明命令“x = 2338”不是赋值,而是将名称x绑定到一个引用 。
此外,前一个对象(拥有值2337)现在位于内存中,引用计数为0,并将被垃圾收集器清理 。
您可以引入一个新名称y,就如C的示例一样:
文章插图
在内存中,您将拥有一个新名称,但不一定是新对象:
文章插图
现在,你可以看到并没有创建一个新的Python对象,只是创建指向同一个对象的新名称 。此外,对象的引用参数增加了1 。您可以检查对象标识来确认它们是否相同:
文章插图
上面的代码表明x和y是相同的对象 。没错:y仍然是不可改变的 。
例如,您可以对有y执行以下操作:
文章插图
添加调用后,将返回一个新的Python对象 。现在,内存看起来像这样:
文章插图
一个新对象被创建,y现在指向新对象 。有趣的是,如果你已经将2339绑定到y,结束状态也是如此:
文章插图
上述语句导致与添加相同的结束内存状态 。回顾一下,在Python中,您不需要分配变量 。而是将名称绑定到引用 。
关于Python中的预实现对象的注释现在您已经了解了如何创建Python对象并将名称绑定到这些对象,现在是时候在机器中抛出一把扳手了 。该扳手叫做预实现对象 。
假设您有以下Python代码:
文章插图
如上所述,x和y这两个名字都指向同一个Python对象 。但是保存1000的Python对象并不能保证总是具有相同的内存地址 。例如,如果将两个数字相加以获得1000,则最终会得到一个不同的内存地址:
文章插图
这一次,"x is y"返回False 。如果这令人困惑,别担心 。以下是执行此代码时发生的步骤:
1.创建Python对象(1000)
2.将名称分配x给该对象
3.创建Python对象(499)
4.创建Python对象(501)
5.将这两个对象一起添加
6.创建一个新的Python对象(1000)
7.将名称分配y给该对象
技术说明:只有在REPL中执行此代码时,才会执行上述步骤 。如果您采用上面的示例,将其粘贴到一个文件中,然后运行该文件,那么您会发现"x is y"将返回True 。
这是因为编译器很聪明 。CPython编译器尝试进行称为窥孔优化的优化,这有助于尽可能地保存执行步骤 。有关详细信息,您可以查看CPython的窥孔优化器源代码 。
这不是浪费吗?嗯,是的,这是你为Python所有巨大好处付出的代价 。您永远不必担心如何清理这些中间对象,甚至都不需要知道它们存在!令人高兴的是,这些操作相对较快,并且直到现在你都不需要去理解这些细节 。
Python核心开发人员也睿智地注意到了这种浪费,并决定进行一些优化 。这些优化产生了令新手感到惊讶的行为:
推荐阅读
- 酷暑难耐的时候如何选择,冷饮or热茶
- Python8个最常用的内置函数
- 初学者如何区分Html5开发和前端开发
- 如何从0开始,搭建企业的实时数据中台?
- 女性喝普洱茶应注意哪些事项
- 如何辨别茶叶好坏 你知道这些吗
- 从古籍中了解古人是如何养生的
- 太极拳的基本功练习 肩臂功
- 你年四季应该如何饮茶呢
- 刹车你会踩吗?看完提升50%驾驶技巧!