来源:Python 技术「ID: pythonall」
上一次我们介绍了一个有用的代码可视化工具Python Tutor,说到我们还要通过这个工具再探讨一下Python引用相关的话题。因此有了本文。
观察代码框下方的布局,可以看到两个按钮之下还有三个下拉菜单,依次点击之后本酱发现了一个神奇的选项:render all objects on the heap (Python/Java)。即图中红框处下拉菜单的第三个选项:
这个选项什么意思呢?翻译一下就是“对于Python和Java两种语言,该工具可以渲染出堆上的所有对象”。
堆是什么意思暂时不用我们操心,只需要知道这么个东西也不影响我们进一步理解接下来的内容。简单地介绍一下,即程序运行过程中,所有的对象都会在堆上创建维护。
换言之这句话的潜在含义就是会将程序中的所有对象渲染出来。
好嘛,说来说去半天了,这个选项到底干嘛的呀?就不能给个痛快话吗?
在之前讨论引用的文章中我们提到过,“在Python中,一切皆对象”。但在之前的图示中有的东西好像不那么一样——整数好像是不可分割的。
使用下面的代码试试:
a = 1
b = a
c = 1
默认图示:
这好家伙,你还敢说什么“一切皆对象”?整数不就是一个高尚的,哦不,纯粹的数字吗?同样是直接赋值,变量a
和b
之间并没有任何关系啊。
这就是这个工具的一点不足了——也说不上不足,实际上也是为用户考虑的结果——但是这样一来,不少粗心的用户,咳,其实是还没开始认真学英语的用户,就很容易忽视下面的选项,从而怀疑自己学到的东西都是个啥。
放一万个心,你学到的东西都没错,错的是这个世界(记得划掉)这个选项。
让我们把选项切换为“render all objects on the heap (Python/Java)”重新执行一次代码:
仿佛有什么奇怪的事情发生了……
那些指向数字“1”的箭头都是什么鬼啊啊啊啊?(怒吼)
这些都是引用啊~
实际上即使是数字,在Python也是以对象的形式存在的,拥有对应的值、对应的引用以及其他一些属性;只是我们很少称其为“整数对象”。
通常来说,像数字这样我们称之为“基本类型”的数据,既有其特殊的一面,在实际编程中也极为常用,为了避免图示过于混乱——毕竟各种箭头拉过来拉过去的,想不乱也不行啊——Python Tutor默认会将基本类型的数据内联于引用它的元素。
到这里,之前的误会也就解开了。并不是因为Python中的数字特殊到不属于对象的范畴,仅仅是因为我们使用的工具默默地对其进行了“优化”。这种优化说不上坏,但是在有的时候确实会对我们造成一定的困扰。
因此,这里本酱特地提醒各位读者老爷一句:在使用工具的时候千万小心,不要过分依赖任何工具。即使是你认为完美的工具,你也不知道它暗地里对你做了什么(优化)。
终于讨论到了变量。
实际上刚看到陈老师的演示视频时,本酱第一时间想到的就是:这未免也太适合用来解释Python的变量了吧!
简直完美符合了本酱的预期,只恨晚生二十年,未能早一步将设想付之行动,blabla……(此处省略后悔词句,嘴炮一时爽)刚巧也印证了刚才本酱关于工具的提醒——好像成了一个鸡生蛋蛋生鸡的循环哈哈。
观察之前的任意一张示例图片,图示中的左侧均为变量帧Frame,也就是对于Python来说,变量本身之间并没有本质上的差异;并且我们早已知道,Python中虽然有不同类型的数据,但是就特定的变量而言,它可以随时随地改变指向为另一种类型的数据。
再进一步,实际上Python中的变量保存的一直都只是程序中各个对象的引用而已,只要规定好对象引用的大小规格,那么完全可以实现“同一个变量在不同的时期保存不同类型的数据”。
举个简单的列子,比如Python中引用规定为8位二进制数,此时虽然引用0x01
和引用0x02
分别对应一个整数对象和一个列表对象,但是对保存8位二进制数的各个变量而言它们是没差的。谁管它到底是一个整数对象还是一个列表对象,就算是一个函数对象,那也和保存引用的变量没有关系。它孙行者造的孽,关我者行孙什么事哈哈。
现在各位读者老爷理解了吧?
在Python中,变量的地位十分之尴尬,变量本身并没有保存任何有效信息,并不像C等语言中变量本身即数据。Python中的变量,说得不好听一点儿,充其量就是一个个的标签,哪儿痛贴哪儿,啊呸,哪儿要贴哪儿,管你是人是鬼,先一发入魂。
大家跟我一起念:Python变量是标签,哪里需要哪里粘(zhan)。
本文通过恰当地使用工具Python Tutor,以一种更加生动形象的方式展示了Python中变量和引用的本质。大家应该善用这样的一些工具来帮助自己学习理解一些看似艰深的概念。
<十分钟!彻底弄懂Python深拷贝与浅拷贝机制>(微博@爱可可-爱生活)
Python Tutor主页
联系客服