#6426·pyo3

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

Author: overcatCreated Sep 17, 2026Updated Sep 18, 2026

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.

bash
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 cb456da1; 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: https://github.com/overcat/pyo3/commit/b3d1fd3277ee15d25943593aaab2cf17d20e7198. If you agree with the approach, I can turn it into a PR.