-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Too restrictive types for bisect.bisect_left
#13347
Comments
This is one of the things of Python's object model that is nearly impossible to model correctly with generics and protocols in the type system. The framing of You would probably need something like HKTs and/or conditional types (and multiple overloads to try both directions of the comparison) to make this work somewhat reliably. In this case it might be fine to just change the You might be better off making |
Thanks @Daverball for looking into this! I just tried the following, which worked and seems more specific than the current signature: @overload
def bisect_left(
a: SupportsLenAndGetItem[SupportsDunderLT[_T]],
x: _T,
lo: int = 0,
hi: int | None = None,
*,
key: None = None,
) -> int: ... I don't understand the type system very well so I'm not sure if this introduces false positives. The overload with a key function would look like this: @overload
def bisect_left(
a: SupportsLenAndGetItem[_T],
x: _U,
lo: int = 0,
hi: int | None = None,
*,
key: Callable[[_T], SupportsDunderLT[_U]],
) -> int: ... This works with the following code (which breaks with the current definition): more_integers = [0, 1, 2]
bisect.bisect_left(more_integers, 1, key=lambda i: MyInteger(i)) |
That seems like a reasonable solution, although you'd either have to change it to |
Also if you wanted to fully support every possible case you would also need to add overloads for the reverse case, where |
The
|
That's not how It will try the most specific dunder first and if it can't find it it will try to calculate it based on the other dunders, so |
The stubs were requiring SupportsRichComparisonT, but bisect only uses __lt__. Be more specific as to which comparison is actually required, which depends on the function. This allows using bisect with types that only implement __lt__. Closes python#13347.
The stubs were requiring SupportsRichComparisonT, but bisect only uses __lt__. Be more specific as to which comparison is actually required, which depends on the function. This allows using bisect with types that only implement __lt__. Closes python#13347.
The stubs were requiring SupportsRichComparisonT, but bisect only uses __lt__. Be more specific as to which comparison is actually required, which depends on the function. This allows using bisect with types that only implement __lt__. Closes python#13347.
That sentence is indeed a bit misleading, it should probably be framed using Although to be fair, you'll probably find almost no examples of classes that only implement |
Thanks for taking the time to explain this. It makes a difference for the lazy programmer who needs to use a key function and support Python 3.8 (then your only choice is to override It took me a long time to understand that this part of the docs means that
I guess one could insert "When a method is not implemented, its reflection is called with swapped arguments." before the "If". But I disgress. |
I'm not sure if this is a MyPy issue or a
typeshed
issue, but I think it's more likely to be intypeshed
.Consider the following minimal working example:
The
MyInteger
class can be compared to itself and to normal integers. I'm using this to bisect the correct value from the list. Admittedly thebisect
documentation isn't super clear regarding whether the function checksint < MyInteger
orMyInteger < int
. CPython, PyPy, and Jython all do the second comparison.MyPy reports the following:
The relevant overload for Python >= 3.10 is as follows:
I think
x
needs not be of the same type as the items ina
. What matters is thata[i] < x
is a valid comparison.When a key function is provided, we have a similar case where
key(a[i]) < x
must be valid.Encountered in sphinx-contrib/doxylink#63.
The text was updated successfully, but these errors were encountered: