Skip to content

gh-87613: Use AC vectorcall for weakref.ref() - #159470

Open
eendebakpt wants to merge 3 commits into
python:mainfrom
eendebakpt:weakref-vectorcall
Open

eendebakpt wants to merge 3 commits into
python:mainfrom
eendebakpt:weakref-vectorcall

Conversation

@eendebakpt

@eendebakpt eendebakpt commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Convert weakref.ref.__new__ to Argument Clinic with the @vectorcall decorator. weakref.ref.__init__, which only validates the arguments that __new__ already consumed, is converted to Argument Clinic as well. This will also improve the signature of weakref.ref.

+------------------------------+---------------+-----------------------+
| Benchmark                    | weakref_base3 | weakref_patch3        |
+==============================+===============+=======================+
| ref(o)                       | 116 ns        | 89.1 ns: 1.31x faster |
+------------------------------+---------------+-----------------------+
| ref(O())                     | 183 ns        | 172 ns: 1.07x faster  |
+------------------------------+---------------+-----------------------+
| ref(o, cb)                   | 121 ns        | 77.9 ns: 1.55x faster |
+------------------------------+---------------+-----------------------+
| o in WeakSet                 | 287 ns        | 216 ns: 1.32x faster  |
+------------------------------+---------------+-----------------------+
| WeakSet.add; WeakSet.discard | 424 ns        | 324 ns: 1.31x faster  |
+------------------------------+---------------+-----------------------+
| Geometric mean               | (ref)         | 1.30x faster          |
+------------------------------+---------------+-----------------------+
Benchmark script
import pyperf
runner = pyperf.Runner()
setup = """
from weakref import ref, WeakSet
class O: pass
o = O()
cb = lambda r: None
ws = WeakSet()
ws.add(o)
"""
runner.timeit("ref(o)", "ref(o)", setup)
runner.timeit("ref(O())", "ref(O())", setup)
runner.timeit("ref(o, cb)", "ref(o, cb)", setup)
runner.timeit("o in WeakSet", "o in ws", setup)
runner.timeit("WeakSet.add; WeakSet.discard", "ws.add(o); ws.discard(o)", setup)

Generated with help from Claude Code

eendebakpt and others added 3 commits October 15, 2026 11:55
Convert weakref.ref.__new__ to Argument Clinic with the @vectorcall
decorator so that creating a weak reference no longer builds an argument
tuple that is then unpacked twice (by __new__ and by __init__), and so
that the call can be specialized as CALL_BUILTIN_CLASS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
It only validates the arguments that __new__ already consumed, so the
generated parser replaces the PyArg_UnpackTuple call and the arity
error message now matches the one from __new__.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Name the Argument Clinic class after tp_name (weakref.ReferenceType) so
that the generated docstring's signature line is recognised, which makes
help(weakref.ref) show the signature and inspect.signature() work. The
argument errors now name ReferenceType instead of ref/__new__/__init__.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cmaloney cmaloney left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. Not a ton of usage but some in the import machinery which will help startup a bit. Have been looking at similar for some common decorators.

Comment thread Objects/weakrefobject.c
@vectorcall
weakref.ReferenceType.__new__ as weakref_ref_new

ob: object

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should this be called "object" to match the docs https://docs.python.org/3/library/weakref.html#weakref.ref

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. This is positional only, so not too important but I think that would indeed be better.

Note: the subclass KeyedRef is not positional only, and uses the name ob.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review type-feature A feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants