8000 TYP: Improved ``ndarray`` augmented assignment operators by jorenham · Pull Request #29862 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

Conversation

jorenham
Copy link
Member
@jorenham jorenham commented Oct 2, 2025

By using type-restricted method-bound type parameters for self in the ndarray.__i{op}__ "augmented assignment" operator methods, they'll now covariantly specialize, and side-step the need for higher-kinded types (sorry about the jargon). I.e., subtypes of ndarray no longer need to override the __i{op}__ methods.
This allows us to get rid of a bunch of duplication in e.g. np.ma.MaskedArray, and users with their own ndaray subclasses are now also able to do the same.

This also addresses the issue described in python/mypy#19171 more rigourously than #29092, since the self-bound type-parameters are now slightly wider. For example the ndarray.__add__ overload that accepts "integer-like array-likes" (_ArrayLikeInt_co) now applies to all np.number arrays, instead of just the np.integer arrays. For floating-like array-likes the np.floating restriction is now similarly widened to np.inexact. I believe this resolves the remaining class of
issues described in python/mypy#19171 (comment) by @david-zwicker.

@jorenham
Copy link
Member Author
jorenham commented Oct 2, 2025

@MarcoGorelli do you think we could also apply this trick to get rid of the other arithmetic dunder overrides in MaskedArray, or do they behave differently?

Comment on lines 3437 to +3442
@overload
def __iadd__(self: NDArray[integer], other: _ArrayLikeInt_co, /) -> ndarray[_ShapeT_co, _DTypeT_co]: ...
def __iadd__(self: _ComplexFloatingArrayT, other: _ArrayLikeComplex_co, /) -> _ComplexFloatingArrayT: ...
@overload
def __iadd__(self: NDArray[floating], other: _ArrayLikeFloat_co, /) -> ndarray[_ShapeT_co, _DTypeT_co]: ...
def __iadd__(self: _InexactArrayT, other: _ArrayLikeFloat_co, /) -> _InexactArrayT: ...
@overload
def __iadd__(self: NDArray[complexfloating], other: _ArrayLikeComplex_co, /) -> ndarray[_ShapeT_co, _DTypeT_co]: ...
def __iadd__(self: _NumberArrayT, other: _ArrayLikeInt_co, /) -> _NumberArrayT: ...
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to flip the overload order here to appease mypy. It started complaining about non-existent overlap once I put the _*ArrayT typars in, demonstrating that the error is a false-positive.

Copy link
github-actions bot commented Oct 2, 2025

Diff from mypy_primer, showing the effect of this PR on type check results on a corpus of open source code:

colour (https://github.com/colour-science/colour)
- colour/colorimetry/tristimulus_values.py:458: error: Argument 1 to "__imul__" of "ndarray" has incompatible type "object"; expected "_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any] | floating[Any]]] | _NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any] | floating[Any]]]] | float | _NestedSequence[float]"  [arg-type]
+ colour/colorimetry/tristimulus_values.py:458: error: No overload variant of "__imul__" of "ndarray" matches argument type "object"  [call-overload]
+ colour/colorimetry/tristimulus_values.py:458: note: Possible overload variants:
+ colour/colorimetry/tristimulus_values.py:458: note:     def __imul__(self, _SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any] | floating[Any]]] | _NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any] | floating[Any]]]] | float | _NestedSequence[float], /) -> ndarray[tuple[Any, ...], dtype[floating[Any]]]
+ colour/colorimetry/tristimulus_values.py:458: note:     def __imul__(self, _SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]] | _NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]] | int | _NestedSequence[int], /) -> ndarray[tuple[Any, ...], dtype[floating[Any]]]

@charris
Copy link
Member
charris commented Oct 9, 2025

@MarcoGorelli Ping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0