为什么不同数据类型的地址不同[Python]?

时间:2017-08-26 12:50:45

标签: python types memory-address

>>> 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. 为什么随后的声明在地址上有相当大的差异,与数据类型的大小相比较?
  3. 更新#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如何将地址分配给各种数据类型,特别是(此处)字符串。

3 个答案:

答案 0 :(得分:2)

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

Python还会在其分配的内存中存储更多内容,而不仅仅是您提供的变量。 IDE也在该区域运行。因此,在两个分配之间可能存储了一些其他变量。

对于更新#1,请查看this

答案 1 :(得分:1)

id碰巧是CPython中的地址是一个实现细节;它们只能保证与同时存在的对象不同。

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

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

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

答案 2 :(得分:1)

首先,我们应该从Python开始以与C相同的方式开始。在C中,数组只是一块内存。在Python中,它是一个对象。 id()c的{​​{1}}与此结果不同。

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

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

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

  

我有这个疑问,因为我首先学习了C ++(说实话,Turbo C ++)和字符串&#39; Python中定义的地址与C ++中的地址有很大不同。我想这在Python中没问题,因为我们无法通过Python中的地址访问对象,我是对的吗?

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

c[0]

您可以看到>>> for c in "hobo": ... print c, id(c) ... h 4434994600 o 4434861432 b 4434859712 o 4434861432 的字符串共享相同的地址 - BTW,示例是Python 2,但Python 3中存在相同的质量。

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

  

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

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

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