Weakly Referencable Object

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.

1 Like

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. :pray:

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.

1 Like

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 or Py_TPFLAGES_MANAGED_WEAKREF (direct or indirect) to avoid the exception to check rather than keep everything consistent with the PyWeakref_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 :stuck_out_tongue:


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.