The getitem operator

This prototypes __getitem__ using the Python interface, introducing any fancy features we'd need to pull off that. If that won't work, we'll roll our own __cgetitem__ with an easier compilable interface, at least for now.

How Python getitem works

   1 >>> class A:
   2 ...     def __getitem__(self, idx): print repr(idx)
   3 ...
   4 >>> a = A()
   5 >>> a[2]
   6 2
   7 >>> a[2,3]
   8 (2, 3)
   9 >>> a[...,4]
  10 (Ellipsis, 4)
  11 >>> a[1:2]
  12 slice(1, 2, None)
  13 >>> a[1:2:-1, ..., 4]
  14 (slice(1, 2, -1), Ellipsis, 4)

Prototype

Comment legend:

I'll treat self.data always as the underlying C buffer rather than the Python attribute -- this issue is somewhat orthogonal, and anyway I'd guess that [] would lead to the C "overload" getting selected.

This is inside an cdef class ndarray block in a pxd file.

   1 # Use "generic" (parameter polymorphism) in order to avoid certain typing issues
   2 # that will be explained as we go. "index" will have to be compile-time optimized
   3 # anyway, so can as well make it object.
   4 #
   5 # "self" is generic because in my parameter polymorphism draft, I propose that
   6 # assumptions gets carried over when "generic" is used. I.e., using "generic"
   7 # for self makes sure that one instance of the method is created per
   8 # assumption-combination. (This is, I suppose, only really useful if the method
   9 # is not inlined though. So might make it "object" and rely on inlining optimization
  10 # instead *shrug*)
  11 
  12 cdef generic __getitem__(generic self, object index):
  13     if isinstance(index, int): # ECTO
  14         if not self.ndim == 1: # DBA
  15             return (<object>self)[index] # gets a slice
  16         else:
  17             # Somehow use an assumption, self.dtype, in a type context. If the dtype assumption
  18             # is not made then this will raise compile-time error.
  19             # Since the user is "probably" assigning this to a variable of the right type,
  20             # the "generic" return value will be the correct one (or if not, the return statement
  21             # will turn into raising the correct coercion error)
  22             return (<self.dtype*>(self.data + self.strides[0] * index))[0]
  23     else: # ECTO, is a tuple
  24         # All of the below is CTO, but definitely the hardest part
  25         offset = 0
  26         for idx, item in enumerate(index):
  27             if i.__class__ is slice or i is Ellipsis: break
  28             else: offset += self.strides[idx] * item
  29         else:
  30             # can use direct access
  31             return (<self.dtype*>(self.data + offset))[0]
  32         # Encountered break, fall back to Python
  33         return (<object>self)[index]

enhancements/numpy/getitem (last edited 2009-03-01 01:02:25 by localhost)