Usa*_*agi 45 python memory-address
谁可以给我解释一下这个?所以我一直在python中使用id()命令,并遇到了这个:
>>> id('cat')
5181152
>>> a = 'cat'
>>> b = 'cat'
>>> id(a)
5181152
>>> id(b)
5181152
Run Code Online (Sandbox Code Playgroud)
除了一部分之外,这对我有意义:字符串'cat'在我将其分配给变量之前在内存中有一个地址.我可能只是不明白内存寻址是如何工作的,但是有人可以向我解释这一点,或者至少告诉我应该读一下内存寻址吗?
所以这一切都很好,但这让我更加困惑:
>>> a = a[0:2]+'t'
>>> a
'cat'
>>> id(a)
39964224
>>> id('cat')
5181152
Run Code Online (Sandbox Code Playgroud)
这让我感到很奇怪,因为'cat'是一个地址为5181152的字符串,但是新的a具有不同的地址.所以,如果内存中有两个'cat'字符串,为什么不为id('cat')打印两个地址?我最后的想法是连接与地址的变化有关,所以我尝试了这个:
>>> id(b[0:2]+'t')
39921024
>>> b = b[0:2]+'t'
>>> b
'cat'
>>> id(b)
40000896
Run Code Online (Sandbox Code Playgroud)
我本来可以预测ID是相同的,但事实并非如此.思考?
kin*_*all 52
Python相当积极地重用字符串文字.它这样做的规则是依赖于实现的,但CPython使用了我所知道的两个:
"cat",它始终引用相同的字符串对象.
def foo(): return "pack my box with five dozen liquor jugs"
def bar(): return "pack my box with five dozen liquor jugs"
assert foo() is bar() # AssertionError两个优化都在编译时完成(即,生成字节码时).
另一方面,类似于chr(99) + chr(97) + chr(116)字符串表达式,其值为字符串"cat".在像Python这样的动态语言中,它的值在编译时chr()是不可知的(是一个内置函数,但你可能已经重新赋值)所以它通常不会被实现.因此它id()不同于"cat".但是,您可以使用该intern()函数强制执行字符串.从而:
id(intern(chr(99) + chr(97) + chr(116))) == id("cat") # True
Run Code Online (Sandbox Code Playgroud)
正如其他人所提到的那样,实习是可能的,因为字符串是不可变的.这是不可能改变"cat"到"dog",换句话说.您必须生成一个新的字符串对象,这意味着指向同一字符串的其他名称不会受到影响.
同样,Python也会"c" + "a" + "t"在编译时将仅包含常量(例如)的表达式转换为常量,如下面的反汇编所示.根据上述规则,这些将被优化为指向相同的字符串对象.
>>> def foo(): "c" + "a" + "t"
...
>>> from dis import dis; dis(foo)
1 0 LOAD_CONST 5 ('cat')
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
Dav*_*nan 47
'cat'有一个地址,因为你创建它是为了传递给它id().您尚未将其绑定到名称,但该对象仍然存在.
Python缓存并重用短字符串.但是,如果通过串联组装字符串,则会绕过搜索缓存并尝试重用的代码.
请注意,字符串缓存的内部工作原理是纯粹的实现细节,不应该依赖它.
Ned*_*der 17
所有值必须位于内存中的某个位置.这就是id('cat')产生价值的原因.你把它称为"不存在的"字符串,但它显然确实存在,它还没有分配给一个名称.
字符串是不可变的,所以解释可以做聪明的,比如让文字的所有实例'cat'是相同的对象,以便id(a)和id(b)是相同的.
对字符串进行操作将产生新字符串.这些字符串可能与具有相同内容的先前字符串相同或不同.
请注意,所有这些细节都是CPython的实现细节,它们可以随时更改.您不需要在实际程序中关注这些问题.
Python变量与其他语言中的变量(例如,C)不同.
在许多其他语言中,变量是内存中位置的名称.在这些语言中,不同类型的变量可以引用不同类型的位置,并且相同的位置可以被赋予多个名称.在大多数情况下,给定的内存位置可能会不时更改数据.还有间接引用内存位置的方法(int *p包含地址,在该地址的内存位置,有一个整数.)但是变量引用的实际位置不能改变; 变量是位置.这些语言中的变量赋值实际上是"查找此变量的位置,并将此数据复制到该位置"
Python无法正常工作.在python中,实际对象进入某个内存位置,变量就像位置的标记.Python以与管理变量的方式不同的方式管理存储的值.从本质上讲,python中的赋值意味着"查找此变量的信息,忘记它已引用的位置,并将其替换为此新位置".没有数据被复制.
像python一样工作的langauges的一个共同特征(与我们之前讨论的第一种相反)是某些类型的对象以特殊方式管理; 相同的值被缓存,以便它们不占用额外的内存,因此可以非常容易地比较它们(如果它们具有相同的地址,它们是相同的).这个过程称为实习 ; 虽然动态创建的字符串可能不是,但所有python字符串文字都被实现(除了一些其他类型).
在您的确切代码中,语义对话框将是:
# before anything, since 'cat' is a literal constant, add it to the intern cache
>>> id('cat') # grab the constant 'cat' from the intern cache and look up
# it's address
5181152
>>> a = 'cat' # grab the constant 'cat' from the intern cache and
# make the variable "a" point to it's location
>>> b = 'cat' # do the same thing with the variable "b"
>>> id(a) # look up the object "a" currently points to,
# then look up that object's address
5181152
>>> id(b) # look up the object "b" currently points to,
# then look up that object's address
5181152
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2010 次 |
| 最近记录: |