Which function to override if a reference to the object is incremented/decremented

359 views Asked by At

I have a pretty basic doubt in Python. Is there a function that is called when the ref count of an object is being increased?

I am sure there should be a double underscore method that I can override in my class. Basically I am looking for a ref method in Foo class.

class Foo():
    def __ref__(self):
        print ("refcount increased by 1")

ref1 = Foo()
ref2 = ref1 # prints "refcount increased by 1"
ref3 = ref2 # prints "refcount increased by 1"

PS: I am aware of sys.getrefcount

2

There are 2 answers

0
user2357112 On

There's no such hook. It'd break all kinds of stuff, including C-level code that relies on the ability to incref objects without triggering interpreted code. It'd be incompatible with non-refcounted Python implementations (which is most of them). It'd be incompatible with any hypothetical future non-refcounted CPython implementations (unlikely as such would be). It'd be incompatible with itself, because the mere act of calling or leaving such a method would alter the object's refcount, requiring it to trigger again infinitely, and doing anything with the object inside the method would also modify the refcount and cause another trigger even if you could reach the method body.

0
MisterMiyagi On

There is no special method invoked by the VM for reference counting. Reference counting is an implementation detail of the CPython VM and not visible outside of implementation-specific helpers.

reference count (Python glossary)

The number of references to an object. When the reference count of an object drops to zero, it is deallocated. Reference counting is generally not visible to Python code, but it is a key element of the CPython implementation. The sys module defines a getrefcount() function that programmers can call to return the reference count for a particular object.


CPython internally uses C macros/functions to manage reference counts. For CPython 3.8, the reference count is a C integer and omitting debug actions reference counting is defined as:

static inline void _Py_INCREF(PyObject *op)
{
    op->ob_refcnt++;
}

Getting a reference merely increases the reference count. This is purely a C increment operation, and no Python code can be invoked when increasing the reference count.

// omitting lineno/filename used for debug
static inline void _Py_DECREF(PyObject *op)
{
    _Py_DEC_REFTOTAL;
    if (--op->ob_refcnt != 0) {
    }
    else {
        _Py_Dealloc(op);
    }
}

Releasing a reference decrements the reference count, and immediately triggers de-allocation for unreferenced objects. Decrementing is purely a C decrement operation, and no Python code can be invoked when decreasing the reference count. Only after decrementing the reference count to 0 can _Py_Dealloc eventually invoke Python code via __del__.