我编写了以下代码来检查整数是通过值还是引用传递的。
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
?
答案 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)