Skip to content

Make abstract/dunder methods positional-only. #135312

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
randolf-scholz opened this issue Jun 9, 2025 · 3 comments
Open

Make abstract/dunder methods positional-only. #135312

randolf-scholz opened this issue Jun 9, 2025 · 3 comments
Labels
stdlib Python modules in the Lib dir topic-typing type-feature A feature request or enhancement

Comments

@randolf-scholz
Copy link
Contributor

randolf-scholz commented Jun 9, 2025

Feature or enhancement

It would be nice if certain abstract methods / dunder methods would be defined with positional-only arguments, so that when one subclasses them an appropriate name can be chosen, or they can be defined positional-only in the subclass.1

Code sample in pyright playground1

from typing import overload
from collections.abc import Sequence

class MySequence[T](Sequence[T]):
    def __len__(self): return 0
    @overload
    def __getitem__(self, idx: int, /) -> T: ...
    @overload
    def __getitem__(self, idx: slice, /) -> Sequence[T]: ...
    def __getitem__(self, idx: int | slice, /) -> T | Sequence[T]:  # ❌ override
        return MySequence[T]()

In some cases, the stubs already fake that the argument is positional-only, such as for Container.__contains__:

Personally, I think only changing the stubs would be a pragmatic choice, but I was told by the maintainers that they believe this change should be done in Cpython first.

Backward Compatibility

  1. Changing non-abstract methods can potentially break user code. For example, this is currently legal code at runtime

    from collections.abc import Container.
    Container.__subclasshook__(C=list)  # True
  2. Changing the signature of abstract methods can introduce type-checker errors Code sample in pyright playground1

    from collections.abc import Sequence
    def get(x: Sequence[float], index: int) -> float:
        return x.__getitem__(index=index)

With this in mind, I believe changing abstrac dunder methods to use positional only arguments should be relatively safe, as calling them directly with keyword is very uncommon, and at worst it will introduce type errors.

Personally, I'd also like so see methods like Container.__subclasshook__ use positional-only arguments, but I also understand if this is not feasible due to bc-conerns.

Has this already been discussed elsewhere?

python/typeshed#14071

Footnotes

  1. Note that mypy special cases certain dunder methods, and yields different results than pyright on these examples 2 3

@randolf-scholz randolf-scholz added the type-feature A feature request or enhancement label Jun 9, 2025
@randolf-scholz randolf-scholz changed the title Make dunder methods positional-only in abstract classes. Make abstract methods positional-only. Jun 9, 2025
@randolf-scholz randolf-scholz changed the title Make abstract methods positional-only. Make abstract dunder methods positional-only. Jun 9, 2025
@randolf-scholz randolf-scholz changed the title Make abstract dunder methods positional-only. Make abstract/dunder methods positional-only. Jun 9, 2025
@picnixz picnixz added stdlib Python modules in the Lib dir topic-typing labels Jun 9, 2025
@randolf-scholz
Copy link
Contributor Author

randolf-scholz commented Jun 9, 2025

I did a scan of the collections.abc module to see how often certain methods are called with keyword arguments, here are the results.

EDIT: index/count had some false positive matches due to github search not defaulting to case-sensistive.
EDIT-2: Added non-abstract Mapping/MutableMapping methods with different signatures.

@JelleZijlstra
Copy link
Member

This is probably fine for the dunder methods in 3.15; it technically breaks compatibility but any affected code (if any exists) is extremely questionable.

The non-dunder methods should probably also use positional-only args if we add them today, but making them positional-only now seems a bit riskier.

@serhiy-storchaka
Copy link
Member

Abstract methods define protocol, but accepting keyword arguments was not intentional. For example, list.index() does not accept the keyword argument value. Either list support of the Sequence protocol is incorrect, or the Sequence protocol is defined incorrectly. The same is true for all other builtin and extension collection types.

If the abstract class provides non-abstract implementation of the method, then such change can break user code. But if it is an abstract method, making its arguments positional-only should be safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir topic-typing type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants