Python中的整数是通过值还是引用传递的?

时间:2013-10-16 09:00:27

标签: python

我编写了以下代码来检查整数是通过值还是引用传递的。

foo = 1

def f(bar):
    print id(foo) == id(bar)
    bar += 1
    print foo, bar

f(foo)

我得到的输出是

True
1, 2

从Python文档中,id(object)返回对象的标识。在CPython实现中,这是内存中对象的地址。由于函数体中的第一个语句返回True,这意味着foo已通过引用传递,但为什么最后一个语句打印1, 2而不是2, 2

4 个答案:

答案 0 :(得分:5)

在Python中,就像许多现代OO语言一样

foo = 1

实际上创建了一个值为1的对象,并为别名foo分配了一个引用。 foo的内部类型是PyIntObject。这意味着Python不使用CPU /硬件int类型,它总是使用对象在内部处理数字。正确的术语是“plain integer”,顺便说一句。

但是创建对象非常昂贵。这就是为什么Python为少数数字保留内部缓存的原因。这意味着:

foo = 1
bar = 1
assert id(foo) == id(bar)

这不能保证,这只是实施的副作用。

Python中的数字类型也是不可变的。因此,即使示例中的bar是缓存的int数的别名,更改bar也不会修改内部值。相反,bar指向另一个实例,这就是id更改的原因。

由于上述优化,这也有效:

foo = 1
bar = 1
assert id(foo) == id(bar)

bar += 1
assert id(foo) != id(bar)

bar -= 1
assert id(foo) == id(bar)

答案 1 :(得分:3)

围绕这个“问题”似乎存在很多困惑。 Python中的变量名称实际上是对象的所有引用。变量名的赋值实际上并不是更改对象本身,而是将引用设置为新对象。所以在你的情况下:

foo = 1 #

def test(bar):
    # At this point, "bar" points to the same object as foo.
    bar = 2    # We're updating the name "bar" to point an object "int(2)".
    # 'foo' still points to its original object, "int(1)".
    print foo, bar # Therefore we're showing two different things.

test(foo)

Python的语法类似于C的方式以及许多事情都是语法糖的事实可能令人困惑。记住整数对象是不可变的,foo += 1可能是一个有效的语句似乎很奇怪。实际上,foo += 1实际上等同于foo = foo + 1,两者都转换为foo = foo.__add__(1),实际上会返回一个新对象,如下所示:

>>> a = 1
>>> id (a)
18613048
>>> a += 1
>>> id(a)
18613024
>>>

答案 2 :(得分:1)

发生以下情况:

print id(foo) == id(bar)

身份是一样的。 print foo is bar会产生同样的,BTW。

bar += 1

这被翻译为:

bar = bar.__iadd__(1)

只有当它不起作用或不存在时,它才会调用:

bar = bar.__add__(1)

(我省略了bar = 1.__radd__(bar)也可以调用的情况。)

由于bar指的是一个不可变的数字,而是返回一个不同的对象,因此bar现在引用2,而foo保持不变。< / p>

如果你做了

中的任何一个
print id(foo) == id(bar)
print foo is bar

现在,您看到他们现在指向不同的对象。

答案 3 :(得分:0)

在Python 2中,当前的实现keeps an array of integer objects for all integers between -5 and 256。因此,如果您将变量指定为var1 = 1而将其他变量指定为var2 = 1,则它们都指向同一对象。

Python“变量”是指向对象的标签,而不是可以填充数据的容器,因此在重新分配时,标签指向新对象(而不是包含新数据的原始对象)。请参阅Stack Overflow问题 Python identity: Multiple personality disorder, need code shrink

来到你的代码,我已经介绍了几个print语句,它们将显示变量是按值传递的

foo = 1
def f(bar):
    print id(foo) == id(bar)
    print id(1), id(foo), id(bar) #All three are same
    print foo, bar 
    bar += 1
    print id(bar), id(2)
    print foo, bar

f(foo)