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
#ifdef
here 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
PyTypeObject
struct 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_weaklistoffset
orPy_TPFLAGES_MANAGED_WEAKREF
(direct or indirect) to avoid the exception to check rather than keep everything consistent with thePyWeakref_xxx
family?.- 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.