我编写了以下代码来检查整数是通过值还是引用传递的.
foo = 1
def f(bar):
print id(foo) == id(bar)
bar += 1
print foo, bar
f(foo)
Run Code Online (Sandbox Code Playgroud)
我得到的输出是
True
1, 2
Run Code Online (Sandbox Code Playgroud)
从Python文档中,id(object)返回对象的标识.在CPython实现中,这是内存中对象的地址.由于函数体中的第一个语句返回True,它表示foo已通过引用传递,但为什么最后一个语句打印1, 2而不是2, 2?
在Python中,就像许多现代OO语言一样
foo = 1
Run Code Online (Sandbox Code Playgroud)
实际上创建一个具有该值的对象,1并为该别名分配一个引用foo.foo的内部类型是PyIntObject.这意味着Python不使用CPU /硬件int类型,它总是使用对象在内部处理数字.正确的术语是" 普通整数 ",顺便说一下.
但是创建对象非常昂贵.这就是为什么Python为少数数字保留内部缓存的原因.意思是:
foo = 1
bar = 1
assert id(foo) == id(bar)
Run Code Online (Sandbox Code Playgroud)
这不能保证,这只是实施的副作用.
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)
Run Code Online (Sandbox Code Playgroud)