如何在Python中模拟指针?

如果您曾经使用过像C或者C++这样的低级语言,那么您可能听说过指针 。指针允许您在部分代码上取得更高的效率 。但它们也会给初学者带来困惑,而且还可能导致各种内存管理错误,即使对于专家来说也会如此 。那么它们在Python的哪里?您该如何在Python中模拟指针?
指针在C和C++中广泛应用 。从本质上来说,它们是保存另一个变量内存地址的变量 。有关指针的复习,您可以考虑看一下这篇关于C语言指针的概述 。
通过本文,您会更好地理解Python的对象模型,同时明白为什么Python中不存在真正的指针 。对于需要模仿指针行为的情况,您将学习到如何在没有内存管理噩梦的情况下在Python中模拟指针 。
在本文中,您将
· 了解为什么Python中的指针不存在
· 探索C变量和Python名称之间的区别
· 在Python中模拟指针
· 使用ctypes实现真正的指针
注意:在本文中,“Python”会涉及C中Python的参考实现,也称作CPython 。当文章在讨论该语言的一些内部结构时,这些注释适用于CPython 3.7,但在将来或过去的语言迭代中可能不适用 。
为什么Python没有指针?事实上,我并不知道答案 。Python中的指针本身可以存在吗?可能,但指针似乎违背了Python的禅宗 。指针鼓励隐含的变化而不是明确的变化 。通常,它们很复杂而不是简单,特别是对于初学者 。更糟糕的是,他们会导致你自作自受,或者做一些非常危险的事情,比如从您不被允许的一段内存中读取数据 。
Python倾向于尝试从用户那里抽象出内存地址等实现细节 。Python通常关注可用性而不是速度 。因此,Python中的指针并没有多大意义 。但不要害怕,默认情况下,Python会为您提供使用指针的一些好处 。
理解Python中的指针需要简要介绍Python的实现细节 。具体来说,您需要了解:
1.不可变对象和可变对象
2.Python变量/名称
保留你的内存地址,让我们开始吧 。
Python中的对象在Python中,一切都是对象 。为了证明,你可以打开一个REPL并尝试使用isinstance():

如何在Python中模拟指针?

文章插图
 
此代码向您显示Python中的所有内容确实是一个对象 。每个对象至少包含三个数据:
•引用计数
•类型
•值
引用计数用于内存管理 。要深入了解Python内存管理的内核,您可以阅读Python中的内存管理 。
类型在CPython层使用,用于确保运行时的类型安全性 。最后,值,即与对象关联的实际值 。
但并非所有对象都是相同的 。您还需要了解另一个重要的区别:不可变对象和可变对象 。理解对象类型之间的差异确实有助于阐明Python中的指针的第一层 。
不可变对象和可变对象在Python中,有两种类型的对象;
1. 不可变对象无法更改
2. 可变对象可以更改
理解这种差异是认识Python指针的第一个关键 。以下是常见类型的细分以及它们是否可变或不可变:
如何在Python中模拟指针?

文章插图
 
如您所见,许多常用的基元类型是不可变的 。您可以通过编写一些Python来证明这一点 。您需要Python标准库中的一些工具:
1.id() 返回对象的内存地址 。
2.is 当且仅当两个对象具有相同的内存地址时才返回True 。
再次,您可以在REPL环境中使用运行以下代码:
如何在Python中模拟指针?

文章插图
 
在上面的代码中,您已经将5赋给x 。如果您尝试使用add修改此值,那么您将获得一个新对象:
如何在Python中模拟指针?

文章插图
 
上面的代码似乎修改了x的值,但您得到了一个新对象作为响应 。
str类型也是不变的:
如何在Python中模拟指针?

文章插图
 
同样,经过“+=”操作后s最终会有不同的内存地址 。
福利:“+=”操作会转换成不同的方法调用 。
对于某些对象,如list对象,+=将转换为__iadd__()(就地添加) 。这将修改self并返回相同的ID 。但是,str和int对象没有这些方法,这就导致它们调用的是__add__()而不是__iadd__() 。
有关更多详细信息,请查看Python 数据模型文档 。
试图直接改变字符串s会导致错误:
如何在Python中模拟指针?

文章插图


推荐阅读