【问题标题】:Why the addresses of different datatypes different [Python]?为什么不同数据类型的地址不同[Python]?
【发布时间】:2018-02-04 08:09:39
【问题描述】:
>>> a=5
>>> b=6
>>> id(a)
10914496
>>> id(b)
10914528
>>> c='Hello'
>>> d='World'
>>> id(c)
139973573252184
>>> id(d)
139973616356744
>>> e=(4>5)
>>> f=(4<5)
>>> id(e)
10739968
>>> id(f)
10740000
  1. 为什么string和boolean/int数据类型的地址长度差别这么大?
  2. 为什么后续声明的地址与数据类型的大小相比有很大差异?

更新#1

>>> id(c)
139973616356856
>>> id(c[0])
139973652926112
>>> id(c[1])
139973653190728
>>> id(c[2])
139973653634272
>>> id(c[3])
139973653302104

我有这个疑问是因为我首先学习了 C++(老实说,Turbo C++),并且在 Python 中定义字符串地址的方式与在 C++ 中发生的情况非常不同。我想这在 Python 中是可以的,因为我们无法通过 Python 中的地址访问对象,对吗?

另外,为 c 和 c[0] 设置不同的地址有什么意义?这些问题对某些人来说可能是不必要的,但我很想知道 Python 如何将地址分配给各种数据类型,特别是(这里)字符串。

【问题讨论】:

  • 还要解释一下反对意见,因为这是我在这个网站上的第一个问题。

标签: python types memory-address


【解决方案1】:

根据您计算机的体系结构,数据类型将以不同的字节长度存储在内存中。例如,字符串中的每个 ASCII 字符都需要一个字节来存储它,而整数可以以任何位长度存储,最大长度取决于所存储数字的大小。我不完全确定,但 python 也可能在它分配的内存的不同区域存储不同的数据类型。

Python 在它分配的内存中也存储了更多的东西,而不仅仅是你给它的变量。 IDE 也在该区域运行。所以在两次分配之间可能已经存储了一些其他变量。

对于更新 #1,请查看this

【讨论】:

  • 我明白你的意思。谢谢你。也请看看我的更新#1。
【解决方案2】:

首先,我们应该首先说明 Python 的工作方式与 C 不同。在 C 中,数组只是一块内存。在 Python 中,它是一个对象。因此cc[0]id() 并不相同。

其次,你应该意识到 Python 中的每一件事都是一个对象。在 C 中,当您执行 c[0] 之类的操作时,您正在从一系列内存位置请求第一个值。在 Python 中,情况不一定如此。对于标准列表,它由一个数组支持,但它的地址对您是隐藏的。您看到的是通过id() 获得的对象地址。在这种情况下,c 是一个字符串,但c[0] 也是一个字符串(Python 中没有字符类型)。这意味着当您请求c[0] 时,Python 正在创建一个新字符串来表示您请求的字符(或者更确切地说,子字符串)。幸运的是,Python 实际上并不是每次都创建一个新字符串,因为 Python 会自动执行 1 个字符的字符串。

另外,请记住,Python 对象具有结构并且也会消耗内存。关于 C 的最好的事情之一是能够很好地控制内存布局,但在 Python 中你失去了这方面的能力。另一方面是您不必手动分配和释放内存,这是一种解脱(我做了很多 C 和 Python 编程,所以我看到了好处)。

第三,在 Python 中发生了很多更多的内存分配和释放。根据 Python 的构建方式以及分配内存的底层操作系统策略,可能会发生任何数量的事情以导致地址不按顺序增加。但由于所有东西都是一个对象,所以对所有东西都有一个底层分配。

我有这个疑问是因为我首先学习了 C++(老实说,Turbo C++),并且在 Python 中定义字符串地址的方式与在 C++ 中发生的情况非常不同。我想这在 Python 中是可以的,因为我们无法通过 Python 中的地址访问对象,对吗?

是的,也不是。当您说c[0] 时,引擎盖下正在运行一种特殊方法来从字符串中检索子字符串。这与您在 C++ 中得到的不同。然而,Python 确实有效地将字符串存储为字节序列。因此,仅仅因为您看不到效率检查地址,并不意味着它不存在。另外,正如我上面提到的,c[0] 返回一个新字符串,它代表您想要的子字符串。 Python 在这里很聪明,它会返回一个 1 字符的字符串,但它会是一个实习生字符串。可以看到有些字母的地址是一样的:

>>> for c in "hobo":
...     print c, id(c)
...
h 4434994600
o 4434861432
b 4434859712
o 4434861432

您可以看到"o" 的字符串共享相同的地址--顺便说一句,示例是 Python 2,但在 Python 3 中存在相同的质量。

你是对的,你不能通过它的地址访问对象——至少这不是语言的特性。如何生成 id 是一个实现细节,但您应该指望每个 Python 解释器都这样做。

另外,为 c 和 c[0] 设置不同的地址有什么意义?这些问题对某些人来说可能是不必要的,但我很想知道 Python 如何将地址分配给各种数据类型,特别是(这里)字符串。

我在上面解释了这一点,但回顾一下:cc[0] 与 C 中的不同。在 Python 中,第一个是字符串,第二个是请求包含字符串第一个字符的子字符串。

Python 确实在许多领域使用了竞技场风格的内存管理方案,但在大多数情况下,您不需要关心这一点。如果你好奇,我建议你看看Python source codePython 子目录有许多语言和低级运行时支持位。并且还意识到 Python 也预先缓存了一些东西,这也可以解释您在上面看到的地址差异。

【讨论】:

    【解决方案3】:

    id 恰好是 CPython 中的地址是一个实现细节;它们只保证对于同时存在的对象是不同的。

    您观察到的分组是因为 CPython 预先创建了许多对象,包括 -5256 以及 TrueFalse。在一般情况下,这些值不会出现在任何其他地址,因为它们是不可变类型,所以这成为可能。

    第二个问题,关于字符串的切片,是因为 Python 的字符串对象不相互引用。没有字符类型,因此从字符串中提取字符会生成一个新字符串。同样,其中一些可能会被缓存(内部字符串)。字符串对象的地址不一定是其内容的地址。

    可以使用ctypes 访问您熟悉的 C 类型,但这样做通常很尴尬且有风险。例如,如果您将 Python 字符串传递给更改 C 字符串的函数,则会破坏字符串本身; Python 期望字符串是不可变的,并且可以共享它们并缓存它们的哈希值。

    【讨论】:

      猜你喜欢
      • 2022-07-22
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多