def __setitem__(self, key, value): """ Set a row, or set of rows, in the array. It takes different actions depending on the type of the `key` parameter: if it is an integer, the corresponding table row is set to `value` (a record, list or tuple capable of being converted to the table field format). If `key` is a slice, the row slice determined by it is set to `value` (a NumPy record array, ``NestedRecArray`` or list of rows). In addition, NumPy-style point selections are supported. In particular, if `key` is a list of row coordinates, the set of rows determined by it is set to `value`. Furthermore, if `key` is an array of boolean values, only the coordinates where `key` is ``True`` are set to values from `value`. Note that for the latter to work it is necessary that `key` list would contain exactly as many rows as the table has. .. Note:: When updating the rows of a `VLArray` object which uses a pseudo-atom, there is a problem: you can only update values with *exactly* the same size in bytes than the original row. This is very difficult to meet with ``object`` pseudo-atoms, because ``cPickle`` applied on a Python object does not guarantee to return the same number of bytes than over another object, even if they are of the same class. This effectively limits the kinds of objects than can be updated in variable-length arrays. Example of use:: vlarray[0] = vlarray[0] * 2 + 3 vlarray[99] = arange(96) * 2 + 3 # Negative values for the index are supported. vlarray[-99] = vlarray[5] * 2 + 3 vlarray[1:30:2] = list_of_rows vlarray[[1,3]] = new_1_and_3_rows """ self._v_file._checkWritable() if is_idx(key): # If key is not a sequence, convert to it coords = [key] value = [value] elif isinstance(key, slice): (start, stop, step) = self._processRange(key.start, key.stop, key.step) coords = range(start, stop, step) # Try with a boolean or point selection elif type(key) in (list, tuple) or isinstance(key, numpy.ndarray): coords = self._pointSelection(key) else: raise IndexError("Invalid index or slice: %r" % (key, )) # Do the assignment row by row self._assign_values(coords, value)
def __setitem__(self, key, value): """ Set a row, or set of rows, in the array. It takes different actions depending on the type of the `key` parameter: if it is an integer, the corresponding table row is set to `value` (a record, list or tuple capable of being converted to the table field format). If `key` is a slice, the row slice determined by it is set to `value` (a NumPy record array, ``NestedRecArray`` or list of rows). In addition, NumPy-style point selections are supported. In particular, if `key` is a list of row coordinates, the set of rows determined by it is set to `value`. Furthermore, if `key` is an array of boolean values, only the coordinates where `key` is ``True`` are set to values from `value`. Note that for the latter to work it is necessary that `key` list would contain exactly as many rows as the table has. .. Note:: When updating the rows of a `VLArray` object which uses a pseudo-atom, there is a problem: you can only update values with *exactly* the same size in bytes than the original row. This is very difficult to meet with ``object`` pseudo-atoms, because ``cPickle`` applied on a Python object does not guarantee to return the same number of bytes than over another object, even if they are of the same class. This effectively limits the kinds of objects than can be updated in variable-length arrays. Example of use:: vlarray[0] = vlarray[0] * 2 + 3 vlarray[99] = arange(96) * 2 + 3 # Negative values for the index are supported. vlarray[-99] = vlarray[5] * 2 + 3 vlarray[1:30:2] = list_of_rows vlarray[[1,3]] = new_1_and_3_rows """ self._v_file._checkWritable() if is_idx(key): # If key is not a sequence, convert to it coords = [key] value = [value] elif isinstance(key, slice): (start, stop, step) = self._processRange( key.start, key.stop, key.step ) coords = range(start, stop, step) # Try with a boolean or point selection elif type(key) in (list, tuple) or isinstance(key, numpy.ndarray): coords = self._pointSelection(key) else: raise IndexError("Invalid index or slice: %r" % (key,)) # Do the assignment row by row self._assign_values(coords, value)
def __getitem__(self, key): """Get a row or a range of rows from the array. If key argument is an integer, the corresponding array row is returned as an object of the current flavor. If key is a slice, the range of rows determined by it is returned as a list of objects of the current flavor. In addition, NumPy-style point selections are supported. In particular, if key is a list of row coordinates, the set of rows determined by it is returned. Furthermore, if key is an array of boolean values, only the coordinates where key is True are returned. Note that for the latter to work it is necessary that key list would contain exactly as many rows as the array has. Examples -------- :: a_row = vlarray[4] a_list = vlarray[4:1000:2] a_list2 = vlarray[[0,2]] # get list of coords a_list3 = vlarray[[0,-2]] # negative values accepted a_list4 = vlarray[numpy.array([True,...,False])] # array of bools """ self._g_check_open() if is_idx(key): key = operator.index(key) # Index out of range protection if key >= self.nrows: raise IndexError("Index out of range") if key < 0: # To support negative values key += self.nrows (start, stop, step) = self._process_range(key, key + 1, 1) return self.read(start, stop, step)[0] elif isinstance(key, slice): start, stop, step = self._process_range(key.start, key.stop, key.step) return self.read(start, stop, step) # Try with a boolean or point selection elif type(key) in (list, tuple) or isinstance(key, numpy.ndarray): coords = self._point_selection(key) return self._read_coordinates(coords) else: raise IndexError("Invalid index or slice: %r" % (key, ))
def __getitem__(self, key): """Get a row or a range of rows from the array. If key argument is an integer, the corresponding array row is returned as an object of the current flavor. If key is a slice, the range of rows determined by it is returned as a list of objects of the current flavor. In addition, NumPy-style point selections are supported. In particular, if key is a list of row coordinates, the set of rows determined by it is returned. Furthermore, if key is an array of boolean values, only the coordinates where key is True are returned. Note that for the latter to work it is necessary that key list would contain exactly as many rows as the array has. Examples -------- :: a_row = vlarray[4] a_list = vlarray[4:1000:2] a_list2 = vlarray[[0,2]] # get list of coords a_list3 = vlarray[[0,-2]] # negative values accepted a_list4 = vlarray[numpy.array([True,...,False])] # array of bools """ self._g_check_open() if is_idx(key): # Index out of range protection if key >= self.nrows: raise IndexError("Index out of range") if key < 0: # To support negative values key += self.nrows (start, stop, step) = self._process_range(key, key + 1, 1) return self.read(start, stop, step)[0] elif isinstance(key, slice): start, stop, step = self._process_range( key.start, key.stop, key.step) return self.read(start, stop, step) # Try with a boolean or point selection elif type(key) in (list, tuple) or isinstance(key, numpy.ndarray): coords = self._point_selection(key) return self._read_coordinates(coords) else: raise IndexError("Invalid index or slice: %r" % (key,))
def _interpret_indexing(self, keys): """Internal routine used by __getitem__ and __setitem__""" maxlen = len(self.shape) shape = (maxlen,) startl = numpy.empty(shape=shape, dtype=SizeType) stopl = numpy.empty(shape=shape, dtype=SizeType) stepl = numpy.empty(shape=shape, dtype=SizeType) stop_None = numpy.zeros(shape=shape, dtype=SizeType) if not isinstance(keys, tuple): keys = (keys,) nkeys = len(keys) dim = 0 # Here is some problem when dealing with [...,...] params # but this is a bit weird way to pass parameters anyway for key in keys: ellipsis = 0 # Sentinel if isinstance(key, type(Ellipsis)): ellipsis = 1 for diml in range(dim, len(self.shape) - (nkeys - dim) + 1): startl[dim] = 0 stopl[dim] = self.shape[diml] stepl[dim] = 1 dim += 1 elif dim >= maxlen: raise IndexError("Too many indices for object '%s'" % self._v_pathname) elif is_idx(key): # Protection for index out of range if key >= self.shape[dim]: raise IndexError("Index out of range") if key < 0: # To support negative values (Fixes bug #968149) key += self.shape[dim] start, stop, step = self._process_range( key, key + 1, 1, dim=dim) stop_None[dim] = 1 elif isinstance(key, slice): start, stop, step = self._process_range( key.start, key.stop, key.step, dim=dim) else: raise TypeError("Non-valid index or slice: %s" % key) if not ellipsis: startl[dim] = start stopl[dim] = stop stepl[dim] = step dim += 1 # Complete the other dimensions, if needed if dim < len(self.shape): for diml in range(dim, len(self.shape)): startl[dim] = 0 stopl[dim] = self.shape[diml] stepl[dim] = 1 dim += 1 # Compute the shape for the container properly. Fixes #1288792 shape = [] for dim in range(len(self.shape)): # The negative division operates differently with python scalars # and numpy scalars (which are similar to C conventions). See: # http://www.python.org/doc/faq/programming.html#why-does-22-10-return-3 # and # http://www.peterbe.com/Integer-division-in-programming-languages # for more info on this issue. # I've finally decided to rely on the len(xrange) function. # F. Alted 2006-09-25 # Switch to `lrange` to allow long ranges (see #99). # use xrange, since it supports large integers as of Python 2.6 # see github #181 new_dim = len(range(startl[dim], stopl[dim], stepl[dim])) if not (new_dim == 1 and stop_None[dim]): shape.append(new_dim) return startl, stopl, stepl, shape
def _interpret_indexing(self, keys): """Internal routine used by __getitem__ and __setitem__""" maxlen = len(self.shape) shape = (maxlen, ) startl = numpy.empty(shape=shape, dtype=SizeType) stopl = numpy.empty(shape=shape, dtype=SizeType) stepl = numpy.empty(shape=shape, dtype=SizeType) stop_None = numpy.zeros(shape=shape, dtype=SizeType) if not isinstance(keys, tuple): keys = (keys, ) nkeys = len(keys) dim = 0 # Here is some problem when dealing with [...,...] params # but this is a bit weird way to pass parameters anyway for key in keys: ellipsis = 0 # Sentinel if isinstance(key, type(Ellipsis)): ellipsis = 1 for diml in xrange(dim, len(self.shape) - (nkeys - dim) + 1): startl[dim] = 0 stopl[dim] = self.shape[diml] stepl[dim] = 1 dim += 1 elif dim >= maxlen: raise IndexError("Too many indices for object '%s'" % self._v_pathname) elif is_idx(key): # Protection for index out of range if key >= self.shape[dim]: raise IndexError("Index out of range") if key < 0: # To support negative values (Fixes bug #968149) key += self.shape[dim] start, stop, step = self._process_range(key, key + 1, 1, dim=dim) stop_None[dim] = 1 elif isinstance(key, slice): start, stop, step = self._process_range(key.start, key.stop, key.step, dim=dim) else: raise TypeError("Non-valid index or slice: %s" % key) if not ellipsis: startl[dim] = start stopl[dim] = stop stepl[dim] = step dim += 1 # Complete the other dimensions, if needed if dim < len(self.shape): for diml in xrange(dim, len(self.shape)): startl[dim] = 0 stopl[dim] = self.shape[diml] stepl[dim] = 1 dim += 1 # Compute the shape for the container properly. Fixes #1288792 shape = [] for dim in xrange(len(self.shape)): # The negative division operates differently with python scalars # and numpy scalars (which are similar to C conventions). See: # http://www.python.org/doc/faq/programming.html#why-does-22-10-return-3 # and # http://www.peterbe.com/Integer-division-in-programming-languages # for more info on this issue. # I've finally decided to rely on the len(xrange) function. # F. Alted 2006-09-25 # Switch to `lrange` to allow long ranges (see #99). # use xrange, since it supports large integers as of Python 2.6 # see github #181 new_dim = len(xrange(startl[dim], stopl[dim], stepl[dim])) if not (new_dim == 1 and stop_None[dim]): shape.append(new_dim) return startl, stopl, stepl, shape