Feature or enhancement
// Returns 1 if the pointed to object is dead, 0 if it's alive, and -1 with an error set if `ref` is not a weak reference. int PyWeakref_IsDead(PyObject *ref);
C API Working Group Issue
Motivation
Prior to Python 3.13, you could check if a weak reference is dead via PyWeakref_GetObject(ref) == Py_None, but that function is now deprecated. You might try writing an "is dead" check using PyWeakref_GetRef. For example:
int is_dead(PyObject *ref) { PyObject *tmp; if (PyWeakref_GetRef(&ref, &tmp) < 0) { return -1; } else if (tmp == NULL) { return 1; } Py_DECREF(tmp); return 0; }
In addition to not being ergonomic, the problem with this code is that the Py_DECREF(tmp) may introduce a side effect from a calling a destructor, at least in the free threading build where some other thread may concurrently drop the last reference. Our internal _PyWeakref_IS_DEAD implementation avoids this problem, but it's not possible to reimplement that code using our existing public APIs.
This can be a problem when you need to check if a weak reference is dead within a lock, such as when cleaning up dictionaries or lists of weak references -- you don't want to execute arbitrary code via a destructor while holding the lock.
I've run into this in two C API extensions this week that are not currently thread-safe with free threading:
- CFFI uses a dictionary that maps a string keys to unowned references. I'm working on update it to use
PyWeakReference, but the "is dead" clean-up checks are more difficult due to the above issues. - Pandas cleans up a list of weak references. (The code is not currently thread-safe, and probably needs a lock.)