Repository: numba/numba

Issue:
Add `dtype` property to `List` class
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->

## Feature request

<!--

Please include details of the feature you would like to see, why you would
like to see it/the use case

-->

add a `dtype` property to the `List` class that forwards to the `dtype` of the contained `_list_type`

Expected functionality:
```python
>>> from numba.typed import List
>>> a = List()
>>> a.append(3)
>>> a.dtype
'int64'
```



Discussion:
I've started work on this.
@rohitsanj thanks for submitting this, I have labeled it as a feature request and have added it to the milestone for the next release.

Resolving patch:
diff --git a/numba/typed/listobject.py b/numba/typed/listobject.py
--- a/numba/typed/listobject.py
+++ b/numba/typed/listobject.py
@@ -12,6 +12,7 @@
 from numba.core.extending import (
     overload,
     overload_method,
+    overload_attribute,
     register_jitable,
     intrinsic,
     register_model,
@@ -1246,6 +1247,18 @@ def impl(lst, key=None, reverse=False):
     return impl
 
 
+@overload_attribute(types.ListType, '_dtype')
+def impl_dtype(l):
+    if not isinstance(l, types.ListType):
+        return
+    dt = l.dtype
+
+    def impl(l):
+        return dt
+
+    return impl
+
+
 def _equals_helper(this, other, OP):
     if not isinstance(this, types.ListType):
         return
diff --git a/numba/typed/typedlist.py b/numba/typed/typedlist.py
--- a/numba/typed/typedlist.py
+++ b/numba/typed/typedlist.py
@@ -235,6 +235,12 @@ def _typed(self):
         """
         return self._list_type is not None
 
+    @property
+    def _dtype(self):
+        if not self._typed:
+            raise RuntimeError("invalid operation on untyped list")
+        return self._list_type.dtype
+
     def _initialise_list(self, item):
         lsttype = types.ListType(typeof(item))
         self._list_type, self._opaque = self._parse_arg(lsttype)


Test patch:
diff --git a/numba/tests/test_typedlist.py b/numba/tests/test_typedlist.py
--- a/numba/tests/test_typedlist.py
+++ b/numba/tests/test_typedlist.py
@@ -155,6 +155,34 @@ def test_unsigned_access(self):
         self.assertEqual(L.pop(ui32_1), 2)
         self.assertEqual(L.pop(ui32_0), 123)
 
+    def test_dtype(self):
+
+        L = List.empty_list(int32)
+        self.assertEqual(L._dtype, int32)
+
+        L = List.empty_list(float32)
+        self.assertEqual(L._dtype, float32)
+
+        @njit
+        def foo():
+            li, lf = List(), List()
+            li.append(int32(1))
+            lf.append(float32(1.0))
+            return li._dtype, lf._dtype
+
+        self.assertEqual(foo(), (np.dtype('int32'), np.dtype('float32')))
+        self.assertEqual(foo.py_func(), (int32, float32))
+
+    def test_dtype_raises_exception_on_untyped_list(self):
+
+        with self.assertRaises(RuntimeError) as raises:
+            L = List()
+            L._dtype
+        self.assertIn(
+            "invalid operation on untyped list",
+            str(raises.exception),
+        )
+
     @skip_parfors_unsupported
     def test_unsigned_prange(self):
         @njit(parallel=True)