Python的引用传递

Pul*_*lse 26 python literals python-internals

您好我正在尝试理解Python的引用如何通过工作.我有一个例子:

>>>a = 1
>>>b = 1
>>>id(a);id(b)
140522779858088
140522779858088
Run Code Online (Sandbox Code Playgroud)

这非常有意义,因为a和b都引用了与身份相同的值.我不太明白的是这个例子:

>>>a = 4.4
>>>b = 1.0+3.4
>>>id(a);id(b)
140522778796184
140522778796136
Run Code Online (Sandbox Code Playgroud)

与此示例不同:

>>>a = 2
>>>b = 2 + 0
>>>id(a);id(b)
140522779858064
140522779858064
Run Code Online (Sandbox Code Playgroud)

是因为在第3个例子中,0 int对象被解释器视为"None",并且没有被识别为需要与变量"a"引用的对象不同的身份(2)?而在第二个例子中,"b"是添加两个不同的int对象,而解释器是为要添加的两个对象分配内存,这给变量"a",与变量"b"不同的标识?

wim*_*wim 48

在您的第一个示例中,由于实习,名称ab"引用"相同的对象.赋值语句只产生一个整数,因为它已经重用了一个恰好在内存中已经存在的预先存在的对象.这不是整数的可靠行为:id

>>> a = 257
>>> b = 257
>>> id(a), id(b)
(30610608, 30610728)
Run Code Online (Sandbox Code Playgroud)

如上所示,如果您选择一个足够大的整数,那么它将表现为第二个示例中的浮点数.无论如何,实际的小整数在Python语言中是可选的,这恰好是CPython实现细节:它是一种性能优化,旨在避免创建新对象的开销.我们可以通过缓存常用的整数实例来加快速度,但代价是Python解释器的内存占用量更高.

在处理Python时不要考虑"引用"和"值",适用于C的模型在这里并不能很好地工作.而是想到"名字"和"对象".

名

上图说明了您的第三个示例. 2是一个对象,a并且b是名字.我们可以使用不同的名称指向同一个对象.对象可以没有任何名称存在.

分配变量只会附加名称标签.和删除一个变量只删除名签.如果你记住这个想法,那么Python对象模型将永远不会让你感到惊讶.

  • 我不喜欢使用"引用"这个词,因为它带来了不必要的C行李(有关内存位置的详细信息,因为我们在更高的抽象级别工作,所以我们不需要在Python中关注它).这是*name*因为它存在于某些*名称空间*中. (13认同)
  • 我不明白你不同意的是什么.我已经在答案中写了"*对象可以不带任何名字*存在",例如在`L = [1,[],'hello']`中,其中"内部"列表有一个引用(通过`L [1 ]`)但范围内没有名字.无论您使用什么术语都需要考虑这种示例,因此最好选择不同的单词来独立解释名称和参考的概念. (3认同)
  • @JAB公平地说,我在使用`PyQt`时只看过它.如果你不保留你的小工具的引用,那么所有有趣的事情都可能发生.大部分时间他们只是消失但有时情况稍微有点微弱,例如参见[这个问题](http://stackoverflow.com/questions/42650119/matplotlib-event-listeners-not-funcitoning-in-pyqt -widget /). (2认同)

Jea*_*bre 8

如前所述这里,CPython的缓存从-5到256所以所有变量整数此范围内具有相同价值的份额相同的ID内(我不会说在将来的版本,虽然赌,但是这是当前实现)

对于浮点数没有这样的事情可能是因为存在可能值的"无穷大"(因为浮点数不是无限大而是大),因此与整数相比,通过不同方法计算相同值的机会非常低.

>>> a=4.0
>>> b=4.0
>>> a is b
False
Run Code Online (Sandbox Code Playgroud)

  • 从技术上讲,你应该说_CPython_缓存从-5到256的整数,因为在Python语言的其他实现中可能不是这样. (3认同)