能否用C++的指针/引用来类比解释一下Python中Tuple的“指向不变性”?

lonaysta
  • 10

初学Python,有一定C/C++基础。
看到Tuple的"immutable"的时候产生了这样一个疑问。
根据我的理解,如果Tuple的元素是普通变量(e.g. myInt=5),那创建
myTuple=(myInt,)
的意义就是
myTuple=(myInt的值,)
因此是不变的。

但是如果myTuple=(myInt,myList),虽然myTuple[1]永远都指向myList,但是myList中的内容是可以改变的。看到有人表示这Tuple里的List实际上是myList的引用。那能否用C++的指针/引用来类比统一解释一下这种Tuple元素的immutable特性呢?

【补充一下:比如对于myTuple=(myInt,myList),定义的时候,从意义上感觉(非严谨),就像是用C++写:
myTuple[0]=myInt; //myInt之后发生了什么都和myTuple[0]无关了,myTuple[0]只决定于myInt当前值
&myTuple[1]=myList; //而myTuple[1]更像是myList的一个引用。myList如果变化,myTuple[1]也会变化

于是这里就产生了“同样是对Tuple赋值,却有两种不同的意义”的矛盾。有什么解释方式能调和这种矛盾么?】

表述的不太清楚,希望能有理解了我的疑问的朋友呀。多谢了。

回复
阅读 3.4k
6 个回答

你的类比是错误的。myTuple=(myInt,myList)在任何时候都是:

&myTuple[0]=myInt;
&myTuple[1]=myList;

因为在Python里一切都是对象,myInt也是。tupleimmutable的意思是你无法为其元素重新赋值。也就是你不能改变myTuple[0]myTuple[1]这两个指针变量的值,所以它们永远指向myIntmyList,这一点是确定的。

但是你可以修改tuple中的每个元素所指向的对象本身,前提是这个对象必须是可变的。比如你能够修改myList,因为这是一个可变对象。但是myInt不行,因为整数也是不可变对象,所以你无法修改它。

你把指针理解成一张上面写有数字的小纸条,纸条上面的数字告诉你该去对应哪一个编号的抽屉里面拿东西。

那么 Tuple 是这样的:

  1. 当你有一个 myTuple 的时候,你有一张名字叫 myTuple 的纸条,根据数字你可以找到一个抽屉,抽屉里面有一张或者多张另外的小纸条。并且这些纸条的数量是确定的,直到你把 myTuple 这张纸条扔掉了(或者说 myTuple 上的数字换了另外一个),才有可能会变化。

  2. myTuple 从 (myInt,)变成 (myInt, myList)的过程,实际上是 myTuple 上面的数字改写了,并且向新的数字对应的另外一个抽屉,放进去两张纸条:第一张是原先的 myInt 纸条,第二张是新加进去的 myList 纸条。

  3. 你对 myList 添加或者删除任意元素,其实都是根据 myList 纸条去找对应的抽屉去做事,跟 myTuple 没有多大关系,只不过是 myTuple 里面恰巧有一张纸条的数字,跟 myTuple 纸条的数字是一样的。

就是常指针呗。

RagPanda
  • 1
新手上路,请多包涵

觉得可以用函数传递参数的情景解释,
1.可变对象传引用:可以在原对象上改变,函数内外都持有对该对象的指针,函数内外使用的是一个对象,如果在函数内部改变该对象,函数外部也会改变,类似于引用传递。
2.不可变对象传拷贝:不可变对象不能在原来的内存空间上变化,所以如果要改变其值,解释器会新建一个对象存放新的变量,这个时候函数内外使用的就不是一个对象了--函数外部还是用的以前的对象,而函数内部已经使用了一个全新的对象。

myInt = 5
myList = [3]
print id(myList)  #id: 37216584
myTuple = (myInt, myList)
print myTuple  #(5, [3])
myList.append(4)
print id(myList) #id: 37216584
print myTuple #(5, [3, 4])
myList = [4, 5]
print id(myList)# id: 37258584
print myTuple #(5, [3, 4])

先确定myList是list对象,指向一个地址(或者说是引用,个人觉得像是一个指针),myTuple存有这个引用。因为是myList可变的,所以可以添加删除,但是它的地址都没变,看先后两次的id。如果将myList指向另一个对象,地址改变了。这时改变的myList不会影响myTuple了。因为Tuple保存的那个list对象没有变化,所以与myTuple无关。

在python中,你这里的myInt也是引用,指向某个整数实体,这跟c/c++不一样,在c/c++中myInt就是整数实体本身了;这样一来,Tuple里存的都是引用,区别只是Int是不可变的,而List是可变的;
所以你说的矛盾并不存在。

宣传栏