经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python3 » 查看文章
Python3中的“指针”
来源:cnblogs  作者:DECHIN  时间:2024/2/28 9:12:10  对本文有异议

技术背景

在python中定义一个列表时,我们一定要注意其中的可变对象的原理。虽然python的语法中没有指针,但是实际上定义一个列表变量时,是把变量名指到了一个可变对象上。如果此时我们定义另外一个变量也指到同一个可变对象的话,就会造成一个“联动”的现象。也就是改变其中的一个值时,另一个值也会随之而改变。本文使用的Python版本为Python 3.7.13

测试案例

这里我们先定义一个列表a,然后把这个空的列表a直接赋值给变量b,此时a和b都是一个空的列表:

  1. In [1]: a = []
  2. In [2]: b = a
  3. In [3]: print (a,b)
  4. [] []

那么如果此时我们修改a的值,那么此前被a赋值的变量b是否也会随之改变呢?

  1. In [4]: a.append(1)
  2. In [5]: print (a,b)
  3. [1] [1]
  4. In [6]: a.append(2)
  5. In [7]: print (a,b)
  6. [1, 2] [1, 2]
  7. In [8]: a = [3]
  8. In [9]: print (a,b)
  9. [3] [1, 2]
  10. In [10]: a.append(4)
  11. In [11]: print (a,b)
  12. [3, 4] [1, 2]

从运行结果来看,我们可以发现,当对a先后扩展一个元素1和2时,变量b的值也随之改变,跟a是同步变化的。但是如果把a这个变量名指向一个新的列表上,此时b的值不会发生变化。这就相当于,给变量a赋新的值的时候,变量b指向了a原来的值,而a这个变量名指向了新的数值,此后两者之间的关联就消失了。之所以没有指针定义的python编程语言,会出现这样的情况,就是因为列表类型属于可变参量,所以如果把两个变量指向同一个列表,两个变量的值是会同步的,即使初始的列表不是一个空的列表,结果也是一样的:

  1. In [23]: a = [1]
  2. In [24]: b = a
  3. In [25]: a += [2]
  4. In [26]: print (a,b)
  5. [1, 2] [1, 2]

而且这个同步还是双向的,也就是说,修改a会同步到b,修改b也会同步到a:

  1. In [11]: a = []
  2. In [12]: b = a
  3. In [13]: b.append(5)
  4. In [14]: print (a,b)
  5. [5] [5]

那么除了列表这个数据结构之外,其他类型的数据结构是否存在类似的现象呢?首先用字典类型来测试一下:

  1. In [10]: a = {}
  2. In [11]: b = a
  3. In [12]: print (a,b)
  4. {} {}
  5. In [13]: a[1]=1
  6. In [14]: print (a,b)
  7. {1: 1} {1: 1}

经过测试我们发现,字典也是属于可变参量的类型。除了列表和字典外,其他的就是普通的数值类型和元组Tuple类型,还有一些第三方定义的数据类型,也可以分别测试一下:

  1. In [15]: a = 1
  2. In [16]: b = a
  3. In [17]: a += 1
  4. In [18]: print (a,b)
  5. 2 1
  6. In [19]: a = (1,)
  7. In [20]: b = a
  8. In [21]: a += (2,)
  9. In [22]: print (a,b)
  10. (1, 2) (1,)
  11. In [23]: a = '1'
  12. In [24]: b = a
  13. In [25]: a += '2'
  14. In [26]: print (a,b)
  15. 12 1

测试结果表明,数值类型和元组类型在“链式”赋值之后,是直接把值给了其他变量的,而不是传递一个指针。但是另一个需要引起重视的是,第三方numpy所定义的array,也是一个可变参量:

  1. In [19]: import numpy as np
  2. In [20]: a = np.array([1], np.float32)
  3. In [21]: b = a
  4. In [22]: print (a,b)
  5. [1.] [1.]
  6. In [23]: a[0] = 2
  7. In [24]: print (a,b)
  8. [2.] [2.]

可以发现,a和b两者的结果也是同步变化的。因为没研究过Python的底层实现,也许区分可变参量和非可变参量的方法,就是看其能不能被哈希

  1. In [15]: hash(1)
  2. Out[15]: 1
  3. In [16]: hash([1])
  4. ---------------------------------------------------------------------------
  5. TypeError Traceback (most recent call last)
  6. <ipython-input-16-0579e98ca3ee> in <module>
  7. ----> 1 hash([1])
  8. TypeError: unhashable type: 'list'
  9. In [17]: hash({'1':1})
  10. ---------------------------------------------------------------------------
  11. TypeError Traceback (most recent call last)
  12. <ipython-input-17-b18acecf6a20> in <module>
  13. ----> 1 hash({'1':1})
  14. TypeError: unhashable type: 'dict'
  15. In [18]: hash((1,))
  16. Out[18]: 3430019387558
  17. In [29]: hash(np.array([1.]))
  18. ---------------------------------------------------------------------------
  19. TypeError Traceback (most recent call last)
  20. <ipython-input-29-b9e8d96de6be> in <module>
  21. ----> 1 hash(np.array([1.]))
  22. TypeError: unhashable type: 'numpy.ndarray'
  23. In [30]: hash(np.array([1.]).tobytes())
  24. Out[30]: 1211024724661850177

从结果中我们发现,那些可以被哈希的类型都是非可变参量,也就是在“链式赋值”的过程中不会发生“联动”的类型。

总结概要

假如你在Python中初始化了一个变量a的值,然后用a来初始化另一个变量b,此时你希望得到的b的数值是跟a同步变化的,还是独立变化的呢?Python这个编程语言虽然没有指针类型,但是Python中的可变参量也可以像指针一样,改变一个数值之后,所有指向该数值的可变参量都会随之而改变。就比如说改变a的值,会同步的去改变b的值。那么我们应该对这种类型的赋值有所了解,才能够避免在实际的编程中犯错。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/syc-note.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

原文链接:https://www.cnblogs.com/dechinphy/p/syc-note.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号