Is there a public API that allows me to check whether an object is weakly referencable? I know that you can check the value of the tp_weaklistoffset slot or check for the Py_TPFLAGS_MANAGED_WEAKREF flag to get the answer, but what about having something like PyObject_WeaklyReferencable, PyWeakref_Referencable, or whatever name fits the situation? This would encapsulate things and keep the extension module developer away from the internal stuff.
tp_weaklistoffset and Py_TPFLAGS_MANAGED_WEAKREF are both public APIs, I don’t think it’s necessarily “internal stuff.” You could implement it pretty easily:
static int
PyObject_WeaklyReferencable(PyObject *op)
{
return Py_TYPE(op)->tp_weaklistoffset != 0;
}
Was @ZeroIntensity 's response somehow not clear? The two fields you need are part of the public API. You can implement the function you want as a one liner.
I just put the link to the issue at Github here to refer to the details I explained about my point rather than copy it again, and I keep things easy for anyone to follow and share their thoughts if there is something to share. ![]()
You can call PyWeakref_NewRef and catch the TypeError. Is there a use case where this is inadequate? (Most likely for performance – a failed PyWeakref_NewRef allocates an exception. What kind of code needs a fast path for non-weakref-able objects?)
If there’s a use case, PyObject_IsWeaklyReferenceable sounds like a good addition. It’s not very clear that PyObject_HasAttrString(op, "__weakref__") is the right thing to do; rather than document/promote that operation we might as well give it a proper name.
But if this is just theoretical, checking "__weakref__" is fine.
I agree–but it’s the use case that I’m particularly worried about here. From the issue, such an API intends to solve problems like these:
- This will give the core developers more control over the implementation rather than let the extension developers use
#ifdefhere and there inside their modules in the future.- One stable interface used by all extensions rather than multiple inconsistent interfaces.
- Keep the extension developers away from any internal changes to the
PyTypeObjectstruct and its fields now and in the future.
PyTypeObject is a public API, and so is tp_weaklistoffset. We probably shouldn’t encourage new APIs just to avoid a Py_TYPE(...)->... for “readability.” (If we add this, I can probably think of at least 100 things that could fall under the same umbrella with the same motivation, e.g., why not a PyObject_CanSetAttribute that checks tp_dictoffset/__dict__?)
And these are also concerning:
- Why do I need to change the pattern of my implementation to use
tp_weaklistoffsetorPy_TPFLAGES_MANAGED_WEAKREF(direct or indirect) to avoid the exception to check rather than keep everything consistent with thePyWeakref_xxxfamily?.- Does this make our previous example hide the details of the
PyTypeObject? Is it readable? Do we remove some overhead?
I’m not so sure it’s a good idea to add something for the sole purpose of letting a user read their code with PyWeakref_ instead of PyObject_, or believe that a public API that probably has extra checks would be faster than Py_TYPE(op)->tp_weaklistoffset != 0 ![]()
Where I do see use is in the limited API, where tp_weaklistoffset isn’t an option–CPython could provide a faster function that can check that instead of __weakref__, but I’m not sure we should be focusing on micro-optimizations in the limited API anyway, because that will be slower because of the extra indirection in macros anyway.