5

What I have:
I am creating a dataclass and I am stating the types of its elements:

class Task():  
     n_items: int  
     max_weight: int  
     max_size: int  
     items: numpy.array(Item)  # incorrect way of doing it

What I want to do
I'd like to declare, that items will be a numpy array of obejcts of class "Item"

Jasha
  • 5,507
  • 2
  • 33
  • 44
Ania
  • 105
  • 1
  • 4
  • There is an open issue regarding type annotations for numpy arrays: https://github.com/numpy/numpy/issues/7370 – Jasha Sep 17 '21 at 17:58

3 Answers3

5

You can put ndarray:

import numpy as np

class Task():  
     n_items: int  
     max_weight: int  
     max_size: int  
     items: np.ndarray
Grzegorz Skibinski
  • 12,624
  • 2
  • 11
  • 34
  • Thanks, but it still doesn't show that items will be a numpy array of a particualr type of objects – Ania Mar 26 '20 at 22:49
  • 1
    Hm, I see - I would then consider making ```numpy``` container, as per: https://docs.scipy.org/doc/numpy/user/basics.dispatch.html and force it to take only certain type of objects. – Grzegorz Skibinski Mar 26 '20 at 22:54
  • Well, I've just learned that if you provide a user created class a numpy array data type it'll simply mean dtype=object, as in generic Python object. It answers my question. – Ania Mar 26 '20 at 22:55
  • 1
    You don't have any native ```numpy``` type with restricted ```dtype``` – Grzegorz Skibinski Mar 26 '20 at 22:55
  • 1
    Right - but then ```object``` means everything. So it could be either your custom class, or anything else. You can actually force it to take only one type, but that would mean exactly making custom ```numpy``` container – Grzegorz Skibinski Mar 26 '20 at 22:57
2

You have to use ndarray class type:

import numpy as np

class Task():  
     n_items: int  
     max_weight: int  
     max_size: int  
     items: np.ndarray[<shapeType>, <convertedNumpyGenericType>]

Where <shapeType> is the type of values defining the shape of the array (probably int) and <convertedNumpyGenericType> defines the array data's type. Be careful that you have to "convert" numpy generic types into python ones. You may want to use np.dtype[<generic>] with <generic> the generic numpy type (e.g np.float64)

If you want to set a default value (inside the field dataclass function) you have to do as follows:

items: np.ndarray[_, _] = field(default_factory=lambda: np.zeros(shape=<int>, dtype=<type>))
1

You can use the nptyping package, which offers type hints specifically for Numpy data types.

Unless you want to create a custom Numpy container, the best you can do is to denote your array as a container of typing.Any objects, since support for types beyond the ones mentioned here is lacking.

from nptyping import NDArray, Shape
from typing import Any
import numpy as np


class Item:
    pass


class Foo:
    def __init__(self, bar: NDArray[Shape["1,2"], Any]):
        self.bar = bar


if __name__ == '__main__':
    item = Item()
    foo = Foo(bar=np.array([Item(), Item()], dtype=Item))
    print(foo.bar)

Running this will yield something like

[<__main__.Item object at 0x7f13f0dd9e80>
 <__main__.Item object at 0x7f13f0dd9040>]
sigma
  • 216
  • 1
  • 4