Skip to content

Add a native Container.__contains__#487

Open
tfoutrein wants to merge 1 commit into
python-poetry:masterfrom
AstekGroup:perf-key-container-fastpaths
Open

Add a native Container.__contains__#487
tfoutrein wants to merge 1 commit into
python-poetry:masterfrom
AstekGroup:perf-key-container-fastpaths

Conversation

@tfoutrein
Copy link
Copy Markdown

Summary

First of the small, self-contained, conformance-preserving performance changes discussed in #483.

Container inherits __contains__ from MutableMapping, so key in container goes through self[key]__getitem__item(), which resolves and returns the value — and constructs a NonExistentKey exception on every absent key — only to discard it.

This adds a native Container.__contains__ that resolves the key exactly as item() does (strSingleKey; a non-str/non-Key argument still raises TypeError) and probes self._map directly. For an out-of-order table (a tuple index) it still builds the OutOfOrderTableProxy, so its validation runs exactly as before. This also speeds up Container.__setitem__, which does if key in self on every assignment.

Behaviour — no change

Beyond the existing suite, I ran a differential in check (present / absent / out-of-order / dotted-string / non-str keys) comparing this branch against master: identical results, including the TypeError on a non-string key and the out-of-order proxy path.

Benchmark

Drift-immune A/B in a single process (the new __contains__ vs the inherited __getitem__-based path, interleaved so thermal drift cancels), CPython 3.11, on a mix of present + absent keys:

old (inherited via __getitem__): ~610 ms
new (native __contains__):       ~520 ms
→ ~1.17× faster  (reproducible: 1.17× across runs)

The win is mostly from not constructing/raising NonExistentKey on absent-key membership.

Verification

  • pytest tests/ (incl. the toml-test conformance submodule): 969 passed, unchanged from master.
  • ruff check + ruff format --check: clean.
  • mypy (1.19.1): no new errors. The single # type: ignore[arg-type] mirrors the existing SingleKey(key) call in item() (which also raises TypeError on a non-string argument).

Context: this is harness-assisted work — every change is individually benchmarked and gated (full test suite incl. conformance, a differential guard, ruff + mypy) before it can land, and I review and stand behind each PR personally. Happy to slice the rest of #483 into further small PRs.

Container inherits __contains__ from MutableMapping, so `key in container`
goes through __getitem__ -> item(), which resolves and returns the value
(and constructs a NonExistentKey on every absent key) only to discard it.

Resolve the key exactly as item() does (str -> SingleKey; a non-str/non-Key
argument still raises TypeError) and probe _map directly. For an out-of-order
table the OutOfOrderTableProxy is still built so its validation runs as before.
This also speeds up __setitem__, which does `if key in self` on every assignment.

Behaviour-identical: 969 tests pass (incl. toml-test); a differential `in`
check over present/absent/out-of-order/dotted/non-str keys matches master
exactly. ~1.17x faster on membership (drift-immune A/B). Part of python-poetry#483.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant