Skip to content

#[pyfunction] gets METH_STATIC since 0.28, which makes calls slower on CPython 3.11+ #6426

Description

@overcat

Bug Description

Since PyO3 0.28, every module-level #[pyfunction] is created with the METH_STATIC flag. A function with one parameter has ml_flags 0xa2 (METH_FASTCALL | METH_KEYWORDS | METH_STATIC). With PyO3 0.27.2 it has 0x82.

The flag has two effects:

  • function.__self__ is None. With 0.27.2 it is the module, as it is for CPython's own builtin functions such as math.sqrt.
  • On CPython 3.11 and newer, a call of a function that has parameters and no **kwargs is about 2 to 4 ns slower. For a function with an empty body this is 10 to 21%. Functions without parameters and functions with **kwargs are not slower. CPython 3.9 and 3.10 are not affected.

I found this while benchmarking fastcrc after upgrading PyO3 from 0.26 to 0.29.2.

Steps to Reproduce

A reproduction is at https://github.com/overcat/pyo3-meth-static-repro. It defines pairs of functions with empty bodies. One function of each pair is a plain #[pyfunction]. The other one uses pass_module, which does not get the flag, and is the control.

git clone https://github.com/overcat/pyo3-meth-static-repro
cd pyo3-meth-static-repro
python -m venv .venv
.venv/bin/pip install .
.venv/bin/python repro.py

Output with CPython 3.14.6 and PyO3 0.29.2:

               plain #[pyfunction]             #[pyfunction(pass_module)]
               ml_flags  __self__  ns/call     ml_flags  __self__  ns/call     difference
no parameters  0x0024    None         13.1     0x0004    module       13.0      +0.1 ns   +1%
one parameter  0x00a2    None         19.6     0x0082    module       16.4      +3.3 ns  +20%
**kwargs       0x0023    None         16.8     0x0003    module       16.7      +0.1 ns   +1%

0x0020 = METH_STATIC

With PyO3 0.27.2, both columns show the same flags, __self__ is the module in both, and the differences are 0.0 ns.

Your operating system and version

Linux Mint 22.3 (kernel 7.0.0-31-generic, x86-64)

Your Python version (python --version)

Python 3.14.6

Your Rust version (rustc --version)

rustc 1.98.0 (88d9e12ae 2026-08-18)

Your PyO3 version

0.29.2 (also 0.28.2 and main at cb456da; 0.27.2 is not affected)

How did you install python? Did you use a virtualenv?

mise (a precompiled python-build-standalone build), in a virtualenv created with "python -m venv"

Additional Info

This was introduced by #5581. The README of the reproduction explains the cause in PyO3 and in CPython. It also has the results for several PyO3 and CPython versions, the instruction counts and a workaround.

There is a candidate fix with a test: overcat@b3d1fd3. If you agree with the approach, I can turn it into a PR.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions