Reputation: 1883
I would like to know why this code prints 4
instead of 3
. Where is the fourth reference?
import sys
def f(a):
print(sys.getrefcount(a))
a = [1, 2, 3]
f(a)
Upvotes: 8
Views: 589
Reputation: 16516
Python 3.11+ works differently now. You'll see 2
instead of 3
with this function:
import ctypes
def get_ref_count(id_: int, un_used): # <----------
return ctypes.c_long.from_address(id_).value
a = [1, 2, 3]
a_id = id(a)
print(get_ref_count(a_id, a)) # prints `2` instead of `3`.
I wanted to explain it a bit more. First I'm gonna use another method to get the number of references using it's id
:
import ctypes
def get_ref_count(id_: int):
return ctypes.c_long.from_address(id_).value
a = [1, 2, 3]
a_id = id(a)
print(get_ref_count(a_id)) # 1
by just passing a
as the argument of the get_ref_count
, the count goes to 3.
import ctypes
def get_ref_count(id_: int, un_used): # <----------
return ctypes.c_long.from_address(id_).value
a = [1, 2, 3]
a_id = id(a)
print(get_ref_count(a_id, a)) # 3
See, I didn't actually do anything with a
. But what happens?
When you call a funcion fn(a)
, Python will load the fn
and a
and puts them on the stack. this is LOAD_NAME
instruction. This instruction calls Py_INCREF()
which increments the number of references by one. Then in order to call that function, it creates a Frame object and pass that reference as the frame's local attribute (Function's parameters are local variables of that function):
from inspect import currentframe
def f(var):
print(currentframe().f_locals) # {'var': [1, 2, 3]}
a = [1, 2, 3]
f(a)
f_locals
is exactly functions's local scope returned by locals()
.
So that's why it incremented by 2.
Upvotes: 1
Reputation: 24077
We can make sense of this in steps:
import sys
print(sys.getrefcount([1, 2, 3]))
# output: 1
import sys
a = [1, 2, 3]
print(sys.getrefcount(a))
# output: 2
import sys
def f(a):
print(sys.getrefcount(a))
f([1, 2, 3])
# output: 3
import sys
def f(a):
print(sys.getrefcount(a))
a = [1, 2, 3]
f(a)
# output: 4
So to reiterate:
a
f
functionf
takesgetrefcount
functionThe reason for no fifth reference, from the parameter getrefcount
takes, is that it's implemented in C, and those don't increase the reference count in the same way. The first example proves this, since the count is only 1 in that.
Upvotes: 6