Skip to content

numpy.typing uint8 becomes signedinteger on multiplication #22631

Closed

Description

@hughperkins

Describe the issue:

When using numpy.typing, multiplying an array with dtype uint8 by any integer converts the typing dtype to signedinteger

Reproduce the code example:

import numpy as np
from numpy.typing import NDArray


def get_uint8() -> NDArray[np.uint8]:
    return np.random.rand(3).astype(np.uint8)


a = get_uint8()  # a is correctly NDArray[np.uint8]
b = a * 1        # b is NDArray[signedinteger]

Error message:

`b` in the code shows as `NDArray[signedinteger]`, instead of `NDArray[np.uint8]`

NumPy/Python version information:

$ python -c 'import sys, numpy; print(numpy.__version__, sys.version)'
1.23.4 3.10.7 (main, Nov 14 2022, 18:57:04) [Clang 14.0.0 (clang-1400.0.29.202)]

Context for the issue:

I'm using numpy.typing to differentiate between some arrays of type uint8 and some arrays of type float32. However, I have to use a cast every time I multiply an array by a number, which compromises the effectiveness of type checking.

Activity

  1. kwsp commented on Nov 20, 2022

    @kwsp

    I believe this is due to numpy's type promotion rules to prevent data loss from mathematical operations. You can test this behavior with np.result_type, and see the linked page for details.

    >>> np.result_type(np.uint8, int)
    dtype('int64')
    

    I agree this is annoying for static type checking, and I understand numpy's rationales for doing type promotion. Certainly, static type annotations currently have no influence on the actual numpy data types at the moment.

  2. hughperkins commented on Nov 20, 2022

    @hughperkins
    Author

    How to work around it? Need to replace all constants with e.g. np.array([1], np.uint8)?

  3. hughperkins commented on Nov 20, 2022

    @hughperkins
    Author

    (Just checked, and this workaround does work)

  4. seberg commented on Dec 7, 2022

    @seberg
    Member

    Replacing constant with uint8 is dangerous if the other side may be a scalar with a small value currently.

    From a runtime perspective, I guess you are effectively getting what you want (although you probably want NEP 50). As I understand it, the problem with typing, although I am not sure if there can be a reasonable solution without NEP 50 (or similar) to remove the value-dependency of the current results.

  5. hughperkins commented on Jan 7, 2025

    @hughperkins
    Author

    awesome 🙌

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions