如何在Python中模拟指针?( 二 )


 
上面的代码失败了,这表明str不支持这种突变,这与str类型是不可变的定义一致 。
与可变对象作对比,例如list类型:

如何在Python中模拟指针?

文章插图
 
此代码显示了两种类型对象的主要区别 。”my_list“最初有一个id 。即使在4被附加到列表后,”my_list“也具有相同的 ID 。这是因为list类型是可变的 。
证明列表可变的另一种方法是赋值:
如何在Python中模拟指针?

文章插图
 
在此代码中,您可以改变“my_list”,将其第一个元素设置为0 。但是,即使在赋值之后,它仍保持原有的ID 。随着可变和不可变对象的出现,Python启蒙之旅的下一步是理解Python的变量生态系统 。
了解变量Python变量在根本上与C或C ++中的变量不同 。事实上,Python甚至没有变量 。Python有名称,而不是变量 。
这可能看起来很迂腐,而且在大多数情况下就是迂腐 。大多数时候,将Python名称视为变量是完全可以接受的,但理解差异很重要 。当您在Python中探寻棘手的指针主题时尤为重要 。
为了帮助理解差异,您可以了解变量如何在C中工作,它们代表什么,然后将其与名称在Python中的工作方式进行对比 。
C中的变量假设您用以下代码来定义变量x:
如何在Python中模拟指针?

文章插图
 
这一行代码在执行时有几个不同的步骤:
1. 为整数分配足够的内存
2. 将值分配2337给该内存位置
3. 指示x指向该值
以简化的内存视图显示,它可能如下所示:
如何在Python中模拟指针?

文章插图
 
在这里,您可以看到该变量x具有伪内存位置0x7f1和值2337 。如果在程序中稍后要更改其x的值,则可以执行以下操作:
如何在Python中模拟指针?

文章插图
 
上面的代码给变量x分配了一个新的值2338,从而覆盖了以前的值 。这意味着变量x是可变的 。更新的内存布局显示新值:
如何在Python中模拟指针?

文章插图
 
请注意,x的位置没有改变,只是改变了值 。这是一个重要的观点 。这意味着x 是内存位置,而不仅仅是名称 。
另一种思考这个概念的方法是在所有权方面 。从某种意义上说,x拥有内存位置 。首先,x恰好是一个可以存储整数的空盒子,可以用来存储整数值 。
当您给x赋值时,您将向x拥有的盒子中放入一个值 。如果你想引入一个新的变量(y),你可以添加这行代码:
如何在Python中模拟指针?

文章插图
 
此代码创建一个名为y的盒子,并将x的值复制到y盒子中 。现在内存布局将如下所示:
如何在Python中模拟指针?

文章插图
 
注意新位置0x7f5的y 。即使将x的值复制到y,但是变量y在内存中拥有新地址 。因此,您可以覆盖y的值而不影响x的值:
如何在Python中模拟指针?

文章插图
 
现在内存布局将如下所示:
如何在Python中模拟指针?

文章插图
 
同样,你修改的是y的值,而不是它的位置 。此外,您始终没有影响原始的x变量 。这与Python名称的工作方式形成鲜明对比 。
Python中的名称Python没有变量 。它有名字 。是的,这是一个迂腐点,你当然可以随意使用术语变量 。重要的是要知道变量和名称之间存在差异 。
让我们根据上面的C示例获取等效代码并将其写在Python中:
如何在Python中模拟指针?

文章插图
 
与C类似,上面的代码在执行过程中分解为几个不同的步骤:
1.创建一个 PyObject
2.将PyObject的typecode设置为整数 PyObject
3.将PyObject的值设置为2337
4.创建一个名称 x
5.将x指向新的PyObject
6.将PyObject引用计数增加1
注意:这里的PyObject与Python的对象不一样 。它于CPython特有的并表示所有Python对象的基本结构 。
PyObject被定义为C结构,所以,如果你想知道为什么你不能调用typecode或refcount,这是因为你没有权限直接进入结构 。方法调用如sys.getrefcount()可以帮助您获得一些内部情况 。
在内存中,它可能看起来像这样:


推荐阅读