此程序的Python内存模型

3 投票
3 回答
3267 浏览
提问于 2025-04-17 23:37

我有一个关于下面这个程序的问题,主要是关于存储值和函数的符号,当我在 http://pythontutor.com/ 上运行时的情况。

内存模型

我的问题是:

  1. 在开始解释这个Python程序之前,Python的执行模型在内存中是怎样的?我该如何想象这个内存布局?比如说,C语言的可执行文件有代码区、栈区、堆区、额外数据段等等,这只是举个例子,并不是在比较。

  2. ‘const’是一个32位或64位的内存区域的名字吗?这个区域存储的值是2,并且类型被指定为整数?

  3. 根据图示,add()/sub()/其他函数在对象列中显示。那么,我该如何理解函数作为对象被存储?我该如何想象这一点?

  4. 根据图示,op是一个指向sub()函数的函数指针吗?

3 个回答

3
  1. 在Python中,不用太担心内存的细节和背后的运作。其实,环境(作用域)更为重要。你提到的块和指针的图示是一个很好的方式来理解内存。白色部分展示了全局环境的样子。当调用一个函数时,会创建一个新的(蓝色的)环境。

  2. const是一个变量。在Python中,变量是动态类型的,可以存储任何东西。实际上,Python中的整数不会溢出,可以存储超过264的数字。在这个例子中,const是一个变量(名字有点让人困惑),它的值是数字2

  3. 函数是一种可以调用的代码块的抽象概念。你可以像对待其他值一样把它赋值给一个变量。

  4. 如果你觉得这样更舒服,可以把它看作是一个函数指针,但那样的话你就暴露了自己是个C语言程序员。Python程序员会直接说op的值是函数sub

3
  1. 字典中的字典。字典是Python中最重要的结构,排第一。

  2. 这是当前作用域字典中一个条目的键。它的值是对象 2

  3. 并不是说函数都是对象,而是有些对象是函数。或者是数字。或者是字典。

  4. 这是当前作用域字典中一个条目的键。它的值是 sub

2

每个C语言(编译型语言)程序在执行之前,都会在内存中加载代码、数据、栈、额外部分和堆等几个区域。那么,Python解释器在开始解释Python程序之前,会为每个Python程序创建内存布局吗?如果会的话,我该如何可视化这个内存布局呢?

Python确实有一种内存布局,但其中最重要的部分是堆,因为所有对象都会放在堆里。代码段只是解释器本身,数据段则是解释器的内部状态,栈也是如此。

对于Python程序来说,最相关的就是堆了。不过,这个布局和其他程序的布局是类似的。

const是一个存储值2的32/64位内存区域的名称吗?这个值的类型被指定为整数?

它其实是当前工作空间中的一个名字(这里指的是模块的命名空间),本质上是一个字典,用来在字符串和任意对象之间进行赋值。在这个例子中,它让字符串const指向一个整数对象,这个对象的值是2。(这个对象可以根据情况新建或重用;这没有区别,因为它是不可变的。)

add()/sub()等函数在图中显示在对象列中,那么,我该如何理解函数作为对象存储的呢?我该如何可视化它?

正如我在对Ignacio回答的评论中所写的:

对于函数来说,你有一个对象,它有一些字段,比如包含字节码的代码、参数数量等等。这个对象本身也有方法,比如__get__(),它在内部用于将方法绑定到对象,或者__call__()用于实际的函数调用,还有__format__()__repr__()等。

一个整数对象内部有一个地方用来存储实际的值。在Python 2中是long(),在Python 3中是int(),它存储数据以保持值(比如2)以及所需的长度。此外,它还有很多方法。你可以查看dir(2)的输出,看到它有一堆方法,比如用于格式化、用于算术运算等等。

根据图示,op是指向函数sub()的函数指针吗?

可以这么说,是的。

这里有一个函数对象,它内部知道它的原始名称是sub。但这个信息只是用于显示。

在你的例子中,它是通过两个名字opsub来引用的。因此,引用其中任何一个都会得到相同的结果。

需要注意的是,并没有所谓的“函数指针”,只有引用或名称,它们指向任何类型的对象。对象的类型是固定的,但“引用的类型”并不存在(因为没有这样的概念)。

撰写回答