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
__eq__
's type hint for primitives accept object
while in many cases it returns NotImplemented
#8217
Comments
This is indeed problematic and the natural solution would be an overloads returning @overload
def __eq__(self, other: FloatLike) -> bool: ...
@overload
def __eq__(self, other: object) -> NotImplemented: ... That said, we haven't returned |
I would be opposed to making changes like this in typeshed without having a discussion on typing-sig first. This would be a large change to make. My instinct is to say that we shouldn't be making allowances for the ways in which numpy/pandas (ab)use |
This is not just a numpy problem: class Floaty:
def __init__(self, f: float) -> None:
self._f = f
def __eq__(self, other: object):
if not isinstance(other, float):
return NotImplemented
return other == self._f
print(Floaty(3.0) == 3.0) # True
print(3.0 == Floaty(3.0)) # True This is due to how |
I know, but in general, this doesn't really matter that much, since in general, the only relevant thing to consider is whether the result of
I think that it is useful to continue to enforce this convention in the stubs; in general, doing otherwise is surprising behaviour that I would consider to be a code smell. It is only with numpy/pandas where the precise return type of |
We dont' even need the
I understand your point of view regarding LSP, but the problem you're describing does make writing scientific codes with python much much easier and human understandable, and as a programming language with a large scientist users, I think in these cases it's really ok, and even IMO encouraged to break the LSP.
Again, that's because you're ignoring the scientific use of the language. Imagine you're creating a library that simplifies SIMD parallelization by defining an Finally, My main problem is that the aforementioned type definitions are WRONG. A type definition SHOULD describe the correct ways a function can be used, and a scenario in which the function returns |
I understand that scientific users of the language represent a major portion of the Python community, and I don't want to disregard that :) I remain of the opinion that this would be a very significant change to make, which would affect the Python-typing community at large, and that we should therefore not make any changes in this area without first discussing it on the typing-sig mailing list, so that we can get a broader range of feedback. |
Although I don't think it affects python-typing community at large (as it does not break any code that's working correctly and only allows some other correct uses of the operation to be included in the types), but I understand your point of view. I just don't know how to discuss this issue on the typing-sig mailing list. If that's something that I can do I'll be happy to write my opinion about it there and ask for feedback on it, just let me know where and how I can join and do that. |
I have created https://discuss.python.org/t/make-type-hints-for-eq-of-primitives-less-strict/34240 |
FWIW, I've been using |
If you think about Python's type hints in terms of set theory, |
I can see that after testing it quickly. Pylance language server follows that principle and it makes sense. Not sure why I was under the impression it worked differently. nvm my previous comment then. I only found one place where I added a |
I think all relevant points have been made. (Please reopen, if another maintainer disagrees.) |
As can be seen in builtins.pyi, all primitives are defining their
__eq__
and__ne__
functions in the following manner:This will cause incorrect type errors in cases where the second operand has overloaded
__eq__
or__ne__
in a way that it does not returnbool
. Consider the following example:Here we're trying to create a class that mimics numpy's
NDArray
in a very limited way.Now if I try to check the equality of a
Matrix
with afloat
, the return type will be inferred asMatrix
, since LHS of the operation has a matching__eq__
method which returns matrix (and the returned type in runtime isMatrix
as well)But if I try to check the equality of a
float
with aMatrix
, the returned type will be inferred asbool
because LHS of the operation has a compatible__eq__
(def __eq__(self, __x: object) -> bool
, object andMatrix
ar compatible) while in the runtime because float's eq will return aNotImplemented
, interpreter will try to run the__ne__
function of the RHS which returns aMatrix
.This will create situations where the inferred type of a simple equality check operation does not match the runtime's type, all because
primitives stubs has been defined in a way that is not representative of their runtime behavior.
The text was updated successfully, but these errors were encountered: